请教父组件和子组件状态传递和刷新的问题?

作者站长头像
站长
· 阅读数 4

大家好,组件 B.jsx 的代码如下,大概意思是它里面有一个按钮,可以打开菜单,也可以关闭菜单,切换菜单的打开和关闭

const B = ({ isMenuOpen, isMenuOpenCallback }) => {
  const [localMenuOpen, setLocalMenuOpen] = useState(false);
  const toggleMenu = (event) => {
    setLocalMenuOpen(prevState => {
      const newLocalMenuOpen = !prevState;
      isMenuOpenCallback(newLocalMenuOpen);
      return newLocalMenuOpen;
    });
  };

  useEffect(() => {
    setLocalMenuOpen(isMenuOpen);
  }, [isMenuOpen]);

  return (
    <div>
      <button className="preClass" onClick={toggleMenu} />
      {localMenuOpen && (
        <div className="menubar">这里是菜单的内容</div>
      )}
    </div>
  )
}
export default B

组件 A.jsx 是组件 B 的父组件,即 B 组件被 A 组件引用,部分代码如下

import B from './B'

const handlePageClick = (e) => {
    if (!e.target.closest('.menubar') {
      setIsMenuOpen(false);=
    } 
  };

  useEffect(() => {
    // listener
    document.addEventListener('click', handlePageClick);
    // remove
    return () => {
      document.removeEventListener('click', handlePageClick);
    };
  }, [isMenuOpen]);

return (
    <B 
        otherHandler={() => otherHandler('news')}
        isMenuOpen={isMenuOpen}
        isMenuOpenCallback={(newMenuOpen) => setIsMenuOpen(newMenuOpen)} />
)
}

这些代码实现了当 B 组件中的菜单展开后,点击其父组件 A 中页面任何地方,都能关闭该菜单。但现在遇到的问题是总是有错误警告

Warning: Cannot update a component (A) while rendering a different component (B). To locate the bad setState() call inside B

请问这个该怎么修复呢?

或者说我的需求是点击 B 组件中的按钮可以打开关闭菜单,当菜单打开时,点击 A 组件的任何地方(菜单项除外),都能关闭菜单,有其它什么更合适的方法?

回复
1个回答
avatar
test
2024-06-21

状态都移到父组件即A上就可以了吧

// A.js
import React from 'react';
import B from './B.js';

function A() {
  const [isMenuOpen, setMenuOpen] = React.useState(false);
  const toggleMenu = () => {
    console.log('toggle', isMenuOpen);
    setMenuOpen(!isMenuOpen);
  };
  const closeMenu = (event) => {
    if (event.target.closest('.menubar')) return;
    console.log('closeMenu');
    if (isMenuOpen) setMenuOpen(false);
  };
  return (
    <div class="A" onClick={closeMenu}>
      <B toggleMenu={toggleMenu} isMenuOpen={isMenuOpen} />
    </div>
  );
}

export default A;
// B.js
import React from 'react';

const B = ({ toggleMenu, isMenuOpen }) => {
  return (
    <div>
      <button className="preClass" onClick={toggleMenu}>
        Open{' '}
      </button>
      {isMenuOpen && <div className="menubar">这里是菜单的内容</div>}
    </div>
  );
};
export default B;

stackblitz

报warning应该是因为这段代码Cannot update a component (A) while rendering a different component (B).

  • setLocalMenuOpencallback参数将会在rendering的时候执行。
  • isMenuOpenCallback(newLocalMenuOpen);会触发A组件的更新。

    setLocalMenuOpen(prevState => {
       const newLocalMenuOpen = !prevState;
       isMenuOpenCallback(newLocalMenuOpen);
       return newLocalMenuOpen;
     });
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容