material-ui - 反应钩子 setState 没有正确地重新渲染组件
问题描述
我有一个组件(切换菜单列表),它应该在单击按钮时加载一个子组件(切换菜单项)。
下面是它的工作原理。
'btnId' 初始状态 = null
-> 按钮单击
-> 将状态更新为索引号 1
-> (btnId !== null) && 加载子组件
但是,子组件不会在状态更新时显示。
如果我将初始化状态设置为 1,它会在按钮单击时显示。
toggleMenuList.js
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.log('Toggle Menu List is rendered');
console.log('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);
toggleMenuItems.js
const ToggleMenuItems = ({ handleClose, open, anchorRef, items }) => {
console.log('Toggle Menu Items is rendered.');
console.log('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.log 被解雇)
但它不显示。
解决方案
我用不同的方法解决了这个问题。我将 activeId 状态设置为初始值“null”,在单击按钮时会更新为“clicked button id”。并且仅当“button Id”匹配“activeId”时才加载子组件。
而且我还在子组件中添加了这个条件。
const isOpen = activeId === id;
return (
<Popper
open={isOpen}
这样,当一个按钮的 open 为 true 时,其余的设置为 false。
toggleMenuList.js
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>
);
};
toggleMenuItems.js
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>
);
};
推荐阅读
- dpdk - 在编译 DPDK hello world 时需要帮助
- css - 如何在 SVG 中旋转给定路径附近的路径
- php - 如何通过编辑在.php文件上添加按钮
- react-native - 如何在本机反应中显示滚动视图项目的阴影
- c# - 如何使用 OpenXML 在 Excel 工作表中设置复选框值
- regex - 如何使用正则表达式在 Kotlin 中查找关键字
- python - 从python中的嵌套字典中获取值的最佳方法
- php - PHP 页面是否会因为所述结果正在其他地方被替换/重新计算而获得不完整的查询结果?
- python - Python改成全币种代码
- javascript - 在 Angular 中生成 HTML 到自定义 PDF