-
-
Save bnorton/e40560df501a6803692cdb787ee3d5a0 to your computer and use it in GitHub Desktop.
/* | |
Prompt: | |
We have defined a basic dropdown via the Dropdown and DropdownItem components below, with example usage | |
in the ExampleNav component. The Dropdown and DropdownItem components have some problems, and also | |
have room for improvements (doesn't everything?) A couple items TODO here (make sure to explain with comments!) | |
0. How are you today? 😊 | |
1. Please fix any obvious issues you see with the dropdown. | |
2. Please then make improvements to the dropdown. | |
3. Consider the different ways that this dropdown might be used and what changes would | |
be neccessary to make it more flexible. | |
4. If we wanted to sync this dropdown selection to the server with | |
app.sync('PATCH', 'user', { dropdown_1_state: {true,false} }) where would this be included? | |
5. If we wanted to pass children (like this example) OR a Promise that resolves to an array of items | |
what changes should be made? (just a sentence or two or some code is ok). | |
PS: No need to worry about CSS. | |
*/ | |
import React, {PureComponent} from 'react'; | |
class Dropdown extends PureComponent { | |
constuctor(props) { | |
super(props); | |
this.state = { | |
isOpen: false, | |
}; | |
} | |
toggle() { | |
const {isOpen} = this.state; | |
this.setState({isOpen: isOpen}); | |
} | |
render() { | |
const {isOpen} = this.state; | |
const {label} = this.props; | |
return ( | |
<div className="dropdown"> | |
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button> | |
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu"> | |
{this.props.children} | |
</ul> | |
</div> | |
); | |
} | |
} | |
class DropdownItem extends PureComponent { | |
render() { | |
// TODO implement me | |
} | |
} | |
class ExampleNav extends PureComponent { | |
render() { | |
return ( | |
<nav> | |
<a href="/page1">Page 1</a> | |
<Dropdown label="More items"> | |
<DropdownItem href="/page2">Page 2</DropdownItem> | |
<DropdownItem href="/page3">Page 3</DropdownItem> | |
<DropdownItem href="/page4">Page 4</DropdownItem> | |
</Dropdown> | |
<Dropdown label="Even more items"> | |
<DropdownItem href="/page5">Page 5</DropdownItem> | |
<DropdownItem href="/page6">Page 6</DropdownItem> | |
</Dropdown> | |
</nav> | |
); | |
} | |
} |
import React, { PureComponent } from "react";
class Dropdown extends PureComponent {
// Updated the name from `constuctor` to `constructor`
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}
// Converted this to an arrow function so the `this` is bound to class
toggle = () => {
const { isOpen } = this.state;
// Updated the assignment to use the negated form, for toggle to work
this.setState({ isOpen: !isOpen });
};
render() {
const { isOpen } = this.state;
const { label } = this.props;
return (
<div className="dropdown">
{/* change aria-expended to aria-expanded */}
<button
type="button"
className="dropdown-button"
id="dropdownButton"
aria-haspopup="true"
aria-expanded={isOpen}
onClick={this.toggle}
>
{label}
</button>
<ul
className={`${isOpen ? "dropdown-open" : ""} dropdown-menu`}
aria-labelledby="dropdownButton"
role="menu"
>
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// Returned an anchor element, rendering the props passed
return <a href={this.props.href}>{this.props.children}</a>;
}
}
// Exported the ExampleNav Component
export default class ExampleNav extends PureComponent {
render() {
return (
<nav>
<a href="/page1">Page 1</a>
<Dropdown label="More items">
<DropdownItem href="/page2">Page 2</DropdownItem>
<DropdownItem href="/page3">Page 3</DropdownItem>
<DropdownItem href="/page4">Page 4</DropdownItem>
</Dropdown>
<Dropdown label="Even more items">
<DropdownItem href="/page5">Page 5</DropdownItem>
<DropdownItem href="/page6">Page 6</DropdownItem>
</Dropdown>
</nav>
);
}
}
// I am not sure the middleware app.sync() exists .
import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
//////its "constructor" not constuctor.
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
toggle() {
const {isOpen} = this.state;
this.setState({isOpen: isOpen});
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
return (
<div className="dropdown">
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
/////return
return(
<>
</>
)
}
}
class ExampleNav extends PureComponent {
render() {
return (
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
);
}
}
import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
constructor ==> not spelt right
constuctor(props) {
super(props);
this.state = {
isOpen: false,
this.toggle = this.toggle.bind(this)
};
}
toggle() {
const {isOpen} = this.state;
//Not is included
this.setState({isOpen: !isOpen});
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
return (
<div className="dropdown">
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expended={isOpen} onClick={this.toggle}>{label}</button>
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
Add a return statement
return {this.props.children}
}
}
class ExampleNav extends PureComponent {
render() {
//I think the app.sync should be included here
return (
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
);
}
}
import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
toggle = () => {
const {isOpen} = this.state;
this.setState({isOpen: !isOpen});
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
return (
<div className="dropdown">
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expanded={isOpen} onClick={this.toggle}>{label}</button>
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// TODO implement me
return (
<a href={this.props.href}>
{this.props.children}
</a>
)
}
}
class App extends PureComponent {
render() {
return (
<nav>
<a href="/page1">Page 1</a>
<Dropdown label="More items">
<DropdownItem href="/page2">Page 2</DropdownItem>
<DropdownItem href="/page3">Page 3</DropdownItem>
<DropdownItem href="/page4">Page 4</DropdownItem>
</Dropdown>
<Dropdown label="Even more items">
<DropdownItem href="/page5">Page 5</DropdownItem>
<DropdownItem href="/page6">Page 6</DropdownItem>
</Dropdown>
</nav>
);
}
}
export default App
```html
`import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
toggle = () => {
const {isOpen} = this.state;
this.setState({isOpen: !isOpen});
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
return (
<div className="dropdown">
<button type="button" className="dropdown-button" id="dropdownButton" aria-haspopup="true" aria-expanded={isOpen} onClick={this.toggle}>{label}</button>
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// TODO implement me
return {this.props.children}
}
}
export default class ExampleNav extends PureComponent {
render() {
return (
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
);
}
}`
{
/*
3. Considering other cases would boil down to forms or any kind of interactive UI that changes based on user selection. If it is strictly for navigation then this implementation would work most of the time. In other cases, we would be looking to implement an array and map() to automatically generate our components.
4. If we want to sync it with the server, then we would be looking at an async function in our componentDidUpdate lifecycle method or the
useEffect hook in the case of functional components
5. We would have an empty array as one of our states, the array's state would be updated at the end of the async call.
The array would then be mapped and displayed on the UI
*/
}
import React, {PureComponent} from 'react';
class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
{/*Updated toggle to an arrow function, this now points to class component*/}
toggle = () => {
{/*Updated setState to a function with the isOpen as an argument, which is better practice incase of batch setState calls in application*/}
this.setState(({isOpen}) => ({isOpen: !isOpen}));
}
render() {
const {isOpen} = this.state;
const {label} = this.props;
{/*Updated aria-expended to aria-expanded*/}
return (
<div className="dropdown">
{/*Updated aria-expended to aria-expanded*/}
<button type="button" className="dropdown-button" id="dropdownButton" aria-expanded={isOpen} aria-haspopup="true" onClick={this.toggle}>{label}</button>
{/*Dropdown now works on toggle*/}
<ul className={`${isOpen ? 'dropdown-open' : ''} dropdown-menu`} aria-labelledby="dropdownButton" role="menu">
{isOpen && this.props.children }
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// TODO implement me
return(
{/*Dropdown Item now receives children and renders accordingly*/}
<a href={this.props.href}>{this.props.children}</a>
);
}
}
class ExampleNav extends PureComponent {
render() {
return (
<nav>
<a href="/page1">Page 1</a>
<Dropdown label="More items">
<DropdownItem href="/page2">Page 2</DropdownItem>
<DropdownItem href="/page3">Page 3</DropdownItem>
<DropdownItem href="/page4">Page 4</DropdownItem>
</Dropdown>
<Dropdown label="Even more items">
<DropdownItem href="/page5">Page 5</DropdownItem>
<DropdownItem href="/page6">Page 6</DropdownItem>
</Dropdown>
</nav>
);
}
}
import React, { PureComponent } from "react";
class Dropdown extends PureComponent {
// Changed the name from constuctor
to constructor
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}
// Converted the toggle function to an arrow function so the this
is bound to the class
toggle = () => {
const { isOpen } = this.state;
// Updated the setStateCall to use the opposite of the current state value for the toggle to work
this.setState({ isOpen: !isOpen });
};
render() {
const { isOpen } = this.state;
const { label } = this.props;
return (
<div className="dropdown">
{/* changed aria-expended to aria-expanded */}
<button
type="button"
className="dropdown-button"
id="dropdownButton"
aria-haspopup="true"
aria-expanded={isOpen}
onClick={this.toggle}
>
{label}
</button>
<ul
className={`${isOpen ? "dropdown-open" : ""} dropdown-menu`}
aria-labelledby="dropdownButton"
role="menu"
>
{this.props.children}
</ul>
</div>
);
}
}
class DropdownItem extends PureComponent {
render() {
// Returned an anchor element, rendering the props passed
return {this.props.children};
}
}
// Exported the ExampleNav Component
export default class ExampleNav extends PureComponent {
render() {
return (
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
);
}
}
Uh oh!
There was an error while loading. Please reload this page.