在 IIFE 中使用 React Hooks 打破了钩子的规则

Using React Hooks in in an IIFE breaks rules of hooks

背景

我正在开发一个可以从 UI 中的许多按钮打开的边栏组件。我想 1) 只渲染一次,2) 授予访问权限以更新这些按钮的 isVisible 状态,而无需通过共同的祖先向下钻取道具。

期望与现实

我希望我可以使用自己的 api 方法创建一个上下文来更新内部状态。在我的代码示例中,我尝试使用 IIFE 来执行此操作。

问题

  1. 这怎么打破了钩子的规则?
  2. 我还能如何为此上下文提供更新功能?
export const SidebarContext = createContext((() => {
  const [isVisible, setIsVisible] = useState(false)

  return {
    isVisible,
    toggleVisibility: () => setIsVisible(!isVisible)
  }
})())

createContext() 接收默认值。因此,您正在定义一个立即调用的函数,它的结果将用作上下文的默认值。这就是 useState 中断 this rule:

的地方

Call Hooks from React function components.

为了完成你想要的,你可以这样做:

import React, { createContext, useContext, useState } from "react";

const SidebarContext = createContext();

function Provider({ children }) {

  let [isVisible, setIsVisible] = useState(false);
  let toggle = useCallback(() => setIsVisible(s => !s), [setIsVisible])

  // Pass the `state` and `functions` to the context value
  return (
    <SidebarContext.Provider value={{ isVisible, toggle }}>
      {children}
    </SidebarContext.Provider>
  );
}

function YourButton() {
  let { isVisible, toggle } = useContext(SidebarContext);
  return (
    <div>
      <div>Sidebar is {isVisible : 'open': 'close'}</div>
      <button onClick={toggle}>
        Toggle
      </button>
    </div>
  );
}

function App() {
  return (
    <Provider>
      <YourButton />
    </Provider>
  );
}