То, как я бы разработал это меню, в основном так:
(посмотрите этот рабочий пример: https://stackblitz.com/edit/toggling-menus)
Внутри компонента приложения у меня есть состояние menus
, в котором я храню данные для каждого меню.
На componentDidMount
я генерирую меню и передаю состояние в MenusContainer через реквизиты.
class App extends Component {
constructor() {
super();
this.state = {
menus: []
};
}
componentDidMount(){
const menus = [
{
id: 1,
title: 'Menu one',
content: 'some content for menu 1'
},
{
id: 2,
title: 'Menu two',
content: 'some content for menu 2'
},
{
id: 3,
title: 'Menu three',
content: 'some content for menu 3'
}
];
this.setState({menus})
}
render() {
return (
<div>
<MenusContainer menus={this.state.menus}/>
</div>
);
}
}
MenusContainer будет отвечать за рендеринг меню, повторяя его menus
реквизит и устанавливая текущее меню.
Для этого он будет иметь состояние currentMenu
и метод setMenu, передавая их в качестве реквизитов дочерним элементам DropdownMenu
, отрисованным из props.menus
.
export default class MenusContainer extends React.Component {
constructor(props) {
super();
this.state = {
currentMenu: -1,
}
}
setMenu = (id) => {
if(id === this.state.currentMenu) {
this.setState({currentMenu: -1})
} else {
this.setState({currentMenu: id})
}
}
render() {
return <div id='container'>
{this.props.menus.map((menu, i) => {
return <DropdownMenu
key={i}
data={menu}
currentItem={this.state.currentMenu}
setMenuCallback={this.setMenu}
/>
})}
</div>
}
}
DropdownMenu узнает (из реквизита), какое меню запрашивается в данный момент, и запустит метод для установки себя в качестве текущего меню из своего реквизита.
Обратите внимание, что меню условно отобразит своего содержимого в соответствии с props.currentItem
.
export default class DropdownMenu extends React.Component {
toggleSelf = () => {
const {id} = this.props.data;
this.props.setMenuCallback(id)
}
render() {
return <div className='menu-item' onClick={this.toggleSelf}>
<h1>{this.props.data.title}</h1>
{
this.props.currentItem === this.props.data.id ?
<div>{this.props.data.content}</div> : null
}
</div>
}
}