У меня есть компонент (переключатель списка меню), который должен загружать дочерний компонент (переключать элементы меню) при нажатии кнопки.
Вот как это работает.
Начальное состояние 'btnId' = ноль
-> нажатие кнопки
-> обновить состояние до индекса номер 1
-> (btnId !== null) && загрузить дочерний компонент
Однако дочерний компонент не отображается при обновлении состояния.
Если я устанавливаю состояние инициализации равным 1, оно отображается при нажатии кнопки.
import React, { useState, useRef } from 'react';
import Button from '@material-ui/core/Button';
import { withStyles } from '@material-ui/core/styles';
/* --- Components --- */
import Loader from '../../shared/loader';
const ToggleMenuItems = Loader({
loader: () =>
import('./toggleMenuItems' /* webpackChunkName: 'ToggleMenuItems' */),
});
const styles = theme => ({
...
});
const ToggleMenuList = ({ navAdminList, navAdminItems, classes }) => {
const [open, setOpen] = useState(false);
const [btnId, setBtnId] = useState(null);
const anchorRef = useRef(null);
const handleToggle = async id => {
await setBtnId(id);
return setOpen(prevOpen => !prevOpen);
};
const handleClose = event => {
...
};
console.info('Toggle Menu List is rendered');
console.info('btnId: ', btnId);
return (
<React.Fragment>
<div className = {`nav-menu ${classes.root}`}>
{navAdminList.map(e => (
<Button
key = {e.id}
ref = {anchorRef}
aria-owns = {open ? 'menu-list-grow' : undefined}
aria-haspopup = "true"
onClick = {() => handleToggle(e.id)}
className = {e.className}
>
{e.name}
</Button>
))}
</div>
{btnId !== null && (
<ToggleMenuItems
handleClose = {handleClose}
open = {open}
anchorRef = {anchorRef}
items = {navAdminItems[btnId]}
/>
)}
</React.Fragment>
);
};
export default withStyles(styles)(ToggleMenuList);
const ToggleMenuItems = ({ handleClose, open, anchorRef, items }) => {
console.info('Toggle Menu Items is rendered.');
console.info('open: ', open);
return (
<Popper
open = {open}
anchorEl = {anchorRef.current}
keepMounted
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style = {{
transformOrigin:
placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper id = "menu-list-grow">
<ClickAwayListener onClickAway = {handleClose}>
<MenuList>
{items.map(e => (
<MenuItem key = {e.id} onClick = {handleClose}>
<Link to = {e.to} className = {e.className}>
{e.name}
</Link>
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
);
};
export default ToggleMenuItems;
Вот журналы консоли, которые я получаю.
* On page load
toggleMenuList.js: Toggle Menu List is rendered
toggleMenuList.js: btnId: null
* On button click
toggleMenuList.js: Toggle Menu List is rendered
toggleMenuList.js: btnId: 1
toggleMenuList.js: Toggle Menu List is rendered
toggleMenuList.js: btnId: 1
toggleMenuItems.js: Toggle Menu Items is rendered.
toggleMenuItems.js: open: true
результат
Значение состояния обновляется.
Дочерний компонент, кажется, загружен. (console.info запускается)
Но он не отображается.
Я решил проблему. Спасибо за комментарий :)





Я решил проблему другим способом. Я установил состояние activeId с начальным значением «null», которое обновляется с помощью «идентификатора нажатой кнопки» при нажатии кнопки. И загружайте дочерний компонент только тогда, когда «идентификатор кнопки» соответствует «activeId».
И я также добавляю это условие в дочерний компонент.
const isOpen = activeId === id;
return (
<Popper
open = {isOpen}
Таким образом, когда открытие одной кнопки имеет значение true, для остальных устанавливается значение false.
const ToggleMenuList = ({ navAdminList, navAdminItems, classes }) => {
const [activeId, setActiveId] = useState(null);
const anchorRef = useRef(null);
const handleToggle = id => {
setActiveId(id);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.include(event.target)) {
return;
}
setActiveId(null);
};
return (
<React.Fragment>
<div className = {`nav-menu ${classes.root}`}>
{navAdminList.map(e => (
<div key = {e.id}>
<Button
ref = {anchorRef}
aria-owns = {activeId === e.id ? 'menu-list-grow' : undefined}
aria-haspopup = "true"
onClick = {() => handleToggle(e.id)}
className = {e.className}
>
{e.name}
</Button>
{activeId === e.id && (
<ToggleMenuItems
id = {e.id}
activeId = {activeId}
handleClose = {handleClose}
anchorRef = {anchorRef}
items = {navAdminItems[e.id]}
/>
)}
</div>
))}
</div>
</React.Fragment>
);
};
const ToggleMenuItems = ({ id, activeId, handleClose, anchorRef, items }) => {
const isOpen = activeId === id;
return (
<Popper
open = {isOpen}
anchorEl = {anchorRef.current}
keepMounted
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style = {{
transformOrigin:
placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper id = "menu-list-grow">
<ClickAwayListener onClickAway = {() => handleClose(id)}>
<MenuList>
{items.map(e => (
<MenuItem key = {e.id} onClick = {() => handleClose(id)}>
<Link to = {e.to} className = {e.className}>
{e.name}
</Link>
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
);
};
Можете ли вы сделать минимальный функциональный пример на CodeSandbox?