反应挂钩setState无法正确重新渲染组件

时间:2019-06-04 08:20:37

标签: material-ui react-hooks

我有一个组件(切换菜单列表),应该在单击按钮时加载一个子组件(切换菜单项)。

这是它的工作方式。

'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被解雇了)

  • 但是不会显示。

1 个答案:

答案 0 :(得分:0)

我用另一种方法解决了这个问题。我将activeId状态设置为初始值'null',并在按钮单击时使用'clicked button id'更新。并仅在“按钮ID”与“ activeId”匹配时加载子组件。

我还将这个条件添加到子组件中。

const isOpen = activeId === id;

  return (
    <Popper
      open={isOpen}

这样,当一个按钮的打开为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>
  );
};