Last active
September 7, 2020 14:56
-
-
Save obulaworld/d3fd28e24b5f0d88054e9986f01a9272 to your computer and use it in GitHub Desktop.
Solution to the dropdown problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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