【问题标题】:React Hooks, how to share state between two functionsReact Hooks,如何在两个函数之间共享状态
【发布时间】:2020-06-23 22:51:49
【问题描述】:

我来自 Vue 背景,当 HTML 被拆分为多个部分时,我很难理解如何有条件地显示某些内容。

假设我得到以下结构:

import React, { useState } from "react";
const [mobileNavOpen, setMobileNavOpen] = useState(false);

function Home() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav />}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

如何在 Home() 和 MobileNav() 中访问 [mobileNavOpen, setMobileNavOpen]。基本上,我想要实现的是一个 Home 组件,用户可以在其中按下一个按钮,在该按钮上,MobileMenu 组件打开一个按钮,他们可以使用另一个按钮再次关闭菜单。

现在,倒数第二行const [mobileNavOpen, setMobileNavOpen] = useState(false); 结果是Error: Invalid hook call. Hooks can only be called inside of the body of a function component.,但我会把它放在哪里?

这一行是否应该在 Home() 组件中,并且所有子组件都会发出一个事件来显示或关闭菜单?或者我需要一个状态管理库来做这么简单的事情吗?执行此操作的“React”方式是什么?

【问题讨论】:

    标签: javascript reactjs react-hooks next.js


    【解决方案1】:

    如果您的Home() Component 呈现MobileNav() Component,您应该将const [mobileNavOpen, setMobileNavOpen] = useState(false) 放入Home() 中,例如:

    const Home = () => {
       const [mobileNavOpen, setMobileNavOpen] = useState(false)
    
       return ( 
       <>
        ...
        <MobileNav 
          handleMobileNav={mobileNavOpen}
        />
        ...
       </>)
    }
    
    const MobileNav = ({ handleMobileNav }) => {
    
       return <></>
    }
    

    【讨论】:

      【解决方案2】:

      一种简单的方法是将状态修饰符向下传递给子组件。为此,钩子需要在父组件内移动。

      import React, { useState } from "react";
      
      
      function Home() {
        const [mobileNavOpen, setMobileNavOpen] = useState(false);
        return (
          <div>
            <button
              onClick={(): void => setMobileNavOpen(true)}
              type="button"
              className="btn"
            >
              X
            </button>
            {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen} />}
          </div>
        );
      }
      
      function MobileNav(setMobileNavOpen) {
        return (
          <div>
            <button
              onClick={(): void => setMobileNavOpen(false)}
              type="button"
              className="btn"
            >
              X
            </button>
          </div>
        );
      }
      
      export default Home;
      

      或者,您可以稍微抽象一下,以便您的子组件仅定义所需的内容:

      import React, { useState } from "react";
      
      function Home() {
        const [mobileNavOpen, setMobileNavOpen] = useState(false);
        return (
          <div>
            <button
              onClick={(): void => setMobileNavOpen(true)}
              type="button"
              className="btn"
            >
              X
            </button>
            {mobileNavOpen && <MobileNav onClose={() => setMobileNavOpen(false)} />}
          </div>
        );
      }
      
      function MobileNav(onClose) {
        return (
          <div>
            <button
              onClick={(): void => onClose()}
              type="button"
              className="btn"
            >
              X
            </button>
          </div>
        );
      }
      
      export default Home;
      
      

      docs 提供了一些管理共享状态的良好最佳实践。

      【讨论】:

      • 钩子不能在组件上下文之外使用。您必须将钩子移到 Home 中。
      • @Laszlo 干杯,我已经整理好了!
      【解决方案3】:

      此行是否应该在 Home() 组件中,并且所有子组件都发出事件以显示或关闭菜单?

      是的。 然后将状态传递给 MobileNavComponent

      【讨论】:

        【解决方案4】:
        import React, { useState } from "react";
        
        function Home() {
          const [mobileNavOpen, setMobileNavOpen] = useState(false);
          return (
            <div>
              <button
                onClick={() => setMobileNavOpen(true)}
                type="button"
                className="btn"
              >
                X
              </button>
              {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen} />}
            </div>
          );
        }
        
        function MobileNav({setMobileNavOpen}) {
          return (
            <div>
              <button
                onClick={() => setMobileNavOpen(false)}
                type="button"
                className="btn"
              >
                X
              </button>
            </div>
          );
        }
        
        export default Home;
        
        1. 您必须将 useState 挂钩移动到组件主体
        2. 将状态设置器函数传递给您的子组件

        【讨论】:

          最近更新 更多