React custom components - necrifede/my-dev-setup GitHub Wiki
Here are my react custom components
uiverse.io
based on custom dropdown
The visual structure of a dropdown menu component
HTML could look like this:
<div className="dd-wrapper">
<div className="dd-header">
<div className="dd-header-title"></div>
</div>
<div className="dd-list">
<button className="dd-list-item"></button>
<button className="dd-list-item"></button>
<button className="dd-list-item"></button>
</div>
</div>
Parent-child relations in components
constructor(){
super()
this.state = {
location: [
{
id: 0,
title: 'New York',
selected: false,
key: 'location'
},
{
id: 1,
title: 'Dublin',
selected: false,
key: 'location'
},
{
id: 2,
title: 'California',
selected: false,
key: 'location'
},
{
id: 3,
title: 'Istanbul',
selected: false,
key: 'location'
},
{
id: 4,
title: 'Izmir',
selected: false,
key: 'location'
},
{
id: 5,
title: 'Oslo',
selected: false,
key: 'location'
}
]
}
}
<Dropdown
title="Select location"
list={this.state.location}
/>
<constructor(props){
super(props)
this.state = {
isListOpen: false,
headerTitle: this.props.title
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
render() {
const { isListOpen, headerTitle } = this.state;
const { list } = this.props;
return (
<div className="dd-wrapper">
<button
type="button"
className="dd-header"
onClick={this.toggleList}
>
<div className="dd-header-title">{headerTitle}</div>
{isListOpen
? <FontAwesome name="angle-up" size="2x" />
: <FontAwesome name="angle-down" size="2x" />}
</button>
{isListOpen && (
<div
role="list"
className="dd-list"
>
{list.map((item) => (
<button
type="button"
className="dd-list-item"
key={item.id}
onClick={() => this.selectItem(item)}
>
{item.title}
{' '}
{item.selected && <FontAwesome name="check" />}
</button>
))}
</div>
)}
</div>
)
}
toggleList = () => {
this.setState(prevState => ({
isListOpen: !prevState.isListOpen
}))
}
selectItem = (item) => {
const { resetThenSet } = this.props;
const { title, id, key } = item;
this.setState({
headerTitle: title,
isListOpen: false,
}, () => resetThenSet(id, key));
}
resetThenSet = (id, key) => {
const temp = [...this.state[key]];
temp.forEach((item) => item.selected = false);
temp[id].selected = true;
this.setState({
[key]: temp,
});
}
<Dropdown
title="Select location"
list={this.state.location}
resetThenSet={this.resetThenSet}
/>
toggleItem = (id, key) => {
const temp = [...this.state[key]];
temp[id].selected = !temp[id].selected;
this.setState({
[key]: temp,
});
}
<Dropdown
title="Select location"
list={this.state.location}
toggleItem={this.toggleItem}
/>
render() {
const { list, toggleItem } = this.props;
return (
//
//
<button
type="button"
className="dd-list-item"
key={item.id}
onClick={() => toggleItem(item.id, item.key)}
>
//
//
)
}
static getDerivedStateFromProps(nextProps) {
const { list, title } = nextProps;
const selectedItem = list.filter((item) => item.selected);
if (selectedItem.length) {
return {
headerTitle: selectedItem[0].title,
};
}
return { headerTitle: title };
}
static getDerivedStateFromProps(nextProps) {
const {
list,
title,
titleHelper,
titleHelperPlural
} = nextProps;
const count = list.filter((item) => item.selected).length;
if (count === 0) {
return { headerTitle: title };
}
if (count === 1) {
return { headerTitle: `${count} ${titleHelper}` };
}
if (count > 1) {
return { headerTitle: `${count} ${titleHelperPlural}` };
}
return null;
}
<Dropdown
titleHelper="Location"
titleHelperPlural="Locations"
title="Select location"
list={this.state.location}
toggleItem={this.toggleItem}
/>
close = () => {
this.setState({
isListOpen: false,
});
}
componentDidUpdate(){
const { isListOpen } = this.state;
if(isOpen){
window.addEventListener('click', this.close)
}
else{
window.removeEventListener('click', this.close)
}
}
componentDidUpdate(){
const { isListOpen } = this.state;
setTimeout(() => {
if(isListOpen){
window.addEventListener('click', this.close)
}
else{
window.removeEventListener('click', this.close)
}
}, 0)
}
<button
type="button"
className="dd-list-item"
key={item.id}
onClick={(e) => {
e.stopPropagation();
this.selectItem(item);
}}
>