Skip to content

Instantly share code, notes, and snippets.

@obulaworld
Last active September 7, 2020 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save obulaworld/d3fd28e24b5f0d88054e9986f01a9272 to your computer and use it in GitHub Desktop.
Save obulaworld/d3fd28e24b5f0d88054e9986f01a9272 to your computer and use it in GitHub Desktop.
Solution to the dropdown problem
/*
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.
Please fix any obvious bugs you see with the dropdown, and explain your reasoning.
Please then describe some improvements you would make to the dropdown, and how you would implement them.
Consider the different contexts in which you might use this dropdown and what changes might be neccessary to make it more flexible.
Follow up question: 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
PS: No need to worry about CSS.
*/
//Solution
// Find below useful comments on my reasoning and some improvements i would love to make to this code.
/*
All dropdowns make use of the same state variable which is isOpen. This will cause an issue
as once it is toggled to true wil force all dropdowns to open up. In a case where the user just
wanted to see the just one dropdown, it will be bad to open others too. It is not a good design.
For me to fix this, I will ensure every dropdown has a seperated state value that it is dependent on to avoid
this issue. With this, only the drop down that has the toggled value will open up. Also when this is done, or when
one dropdown is opened, I will close all other dropdowns to give the use maximum focus on the opened dropdown.
Including the app.sync('PATCH', 'user', { dropdown_1_state: {true,false} }) will be on the native application of this script.
*/
import React, { PureComponent } from "react";
import ReactDOM from "react-dom";
/* this class just makes use of state which can still be done is a fucntional compoenent, hence,
it will be suitable to rather use funcional component instead.
*/
class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
// the toggle function needed to be binded to this for it to be able to access this.state
this.toggle = this.toggle.bind(this);
}
toggle() {
const { isOpen } = this.state;
// this.setstate should set isOpen to !isOpen to proper toggle. if not, the dropdown will remain as it is.
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"
// this attribute is aria-expanded not aria-expended
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>
);
}
}
// this class does not make use of state or life-cycle methods, hence, the need to convert to functional component
class DropdownItem extends PureComponent {
render() {
const { href, children } = this.props;
return (
<a href={href}>
<li>{children}</li>
</a>
);
}
}
// this class does not make use of state or life-cycle methods, hence, the need to convert to functional component
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>
);
}
}
ReactDOM.render(<ExampleNav />, document.getElementById("container"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment