-
-
Save bnorton/7bccc6787ffbf67dfe05f75798daf3da 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 and then save your gist. | |
2. Please then make improvements to the dropdown and then save your gist again. | |
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 the dropdown selection to a server with this hypothetial "syncing library" | |
`app.sync('PATCH', 'users/'+app.USER.id, { dropdown_1_state: {true,false} })` where would this be included? Should | |
the state be read again from the server to show the dropdown open/closed on page load? | |
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 or about making it actually run. | |
*/ | |
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 {
/* miss spelling of the keyword constructor */
constructor(props){
super(props);
this.state = {
isOpen: false,
selectedItem: " ",
};
}
// arrow function correction
toggle = () => {
const { isOpen } = this.state;
// Bug: wrong state update
this.setState({ isOpen: !isOpen });
};
onClickItem = val => {
const { selectedItem } = this.state;
const { onChange } = this.props;
if (val !== selectedItem ){
this.setState({
selectedItem: val
});
this.toggle();
if(onChange){
onChange(val);
}
}
};
render(){
const { isOpen, selectedItem } = this.state;
const { label } = this.props;
const childrenWithProps = React.Children.map(this.props.children, child => {
return React.isValidElement(child)
? React.cloneElement(child, { onClickItem: this.onClickItem, selectedItem})
: child
});
return(
<ul className={
${isOpen ? 'dropdown-open' : ''}dropdown-menu
}aria-labelledby="dropdownButton"
role="menu">
{/* Bug: Add a Double Condition Check */}
{isOpen && childrenWithProps}
);
};
class DropdownItem extends PureComponent {
handleClick = () => {
const { href, onClickItem } = this.props;
onClickItem(href);
};
render(){
const { children, selectedItem, href} = this.props;
const isSelected = selectedItem === href;
return (
<li style={{ color: isSelected ? 'red':''}} onClick={this.handleClick}>
{children}
</li>
);
}
}
export default class ExampleNav extends PureComponent {
}
}
class Dropdown extends PureComponent {
//mispelling of contructor
constuctor(props) {
super(props);
this.state = {
isOpen: false,
};
}
toggle() {
const {isOpen} = this.state;
//Error in state update instead of " this.setState({isOpen: !isOpen}"
this.setState({isOpen: isOpen});
}
import React, { PureComponent } from 'react';
class Dropdown extends PureComponent {
// Bug: wrong name
constructor(props) {
super(props);
this.state = {
isOpen: false,
selectedItem: '',
};
}
// Bug: bind or change to arrow function
toggle = () => {
const { isOpen } = this.state;
// Bug: wrong state update
this.setState({ isOpen: !isOpen });
};
onClickItem = val => {
const { selectedItem } = this.state;
const { onChange } = this.props;
if (val !== selectedItem) {
this.setState({ selectedItem: val });
this.toggle();
if (onChange) {
onChange(val);
}
}
};
render() {
const { isOpen, selectedItem } = this.state;
const { label } = this.props;
console.log('selectedItem', selectedItem);
const childrenWithProps = React.Children.map(this.props.children, child => {
return React.isValidElement(child)
? React.cloneElement(child, { onClickItem: this.onClickItem, selectedItem })
: child;
});
return (
{label}
}
}
class DropdownItem extends PureComponent {
handleClick = () => {
const { href, onClickItem } = this.props;
onClickItem(href);
};
render() {
const { children, selectedItem, href } = this.props;
const isSelected = selectedItem === href;
return (
<li style={{ color: isSelected ? 'red' : '' }} onClick={this.handleClick}>
{children}
);
}
}
export default class ExampleNav extends PureComponent {
render() {
return (
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
);
}
}