перехватывать реагирование setState неправильно перерисовывает компонент - PullRequest
0 голосов
/ 04 июня 2019

У меня есть компонент (переключение списка меню), который должен загружать дочерний компонент (переключение элементов меню) при нажатии кнопки.

Вот как это работает.

'btnId'init state = 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 голосов
/ 05 июня 2019

Я решил проблему другим подходом. Я установил состояние activeId с начальным значением «null», которое обновляется с «нажатием кнопки id» при нажатии кнопки. И загружайте дочерний компонент только тогда, когда 'button Id' соответствует 'activeId'.

И я также добавляю это условие в дочерний компонент.

const isOpen = activeId === id;

  return (
    <Popper
      open={isOpen}

Таким образом, когда одна кнопка открыта, истина, а остальные установлены на ложь.

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>
  );
};

...