【问题标题】:Is nesting React Context Provider and consuming those with useContext a problem?嵌套 React Context Provider 并使用 useContext 是一个问题吗?
【发布时间】:2019-08-07 21:11:55
【问题描述】:

使用深度嵌套的 React 上下文提供程序会遇到什么问题?

const AllContextProvider = props => {
  return (
    <UserProvider>
      <ThemeProvider>
        <NotifProvider>
          <TimelineProvider>
            <CertProvider>
              <MenusProvider>
              {props.children}
              </MenusProvider>
            </CertProvider>
          </TimelineProvider>
        </NotifProvider>
      </ThemeProvider>
    </UserProvider>
  );
};

并像这样使用具有上下文依赖关系的嵌套提供程序:

import React, { useContext } from "react";
import { UserContext } from "./UserContext";
import { useLocalStoragePerUser } from "./useLocalStoragePerUser";

const MenusContext = React.createContext();
const { Provider } = MenusContext;

const MenusProvider = props => {
  // Is this context dependencie always "re-trigger" the Menu Context Provider?
  const { user } = useContext(UserContext);

  // Menus Context
  const [menu, setMenu] = useLocalStoragePerUser( "menus", {
      icons: false,
      labels: true,
      leftMenu: true,
    },
    user
  );

  return (
    <Provider value={{ menu, setMenu}} >
      {props.children}
    </Provider>
  );
};

export { MenusProvider, MenusContext };

这种上下文依赖是否总是“重新触发”菜单上下文提供程序? => 特别是关于无用的重新渲染?

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    嵌套上下文不会导致代码出现任何问题。在上述情况下,如果您在MenuContext 中订阅UserContext,则MenuContext 只会在UserContext 更改提供给其提供者的值时重新呈现。但是,除非 MenuContext 更改它传递给 MenuContext Provider 的值,否则订阅 MenuContext 的子代不会重新渲染,也不会重新渲染其他子代

    import React from "react";
    import ReactDOM from "react-dom";
    import { UserProvider } from "./UserProvider";
    import { ThemeProvider } from "./ThemeProvider";
    import { MenusProvider } from "./MenuProvider";
    
    import "./styles.css";
    function Child() {
      console.log("Child render");
      return <div>Menus Child</div>;
    }
    function App() {
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
          <UserProvider>
            <ThemeProvider>
              <MenusProvider>
                <Child />
              </MenusProvider>
            </ThemeProvider>
          </UserProvider>
        </div>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    你可以看到一个DEMO in the codeSandbox here

    P.S. 但是,您必须确保您没有创建新对象 同时将值传递给提供者,否则每次提供者 重新渲染所有订阅其上下文的子节点将重新渲染

    【讨论】:

    • 非常感谢您花时间为这个问题做一个演示。我玩它,然后……就是这样,我开始明白了。我玩弄用户状态:const [user, setUser] = useState("A")const [user, setUser] = useState({name: "A"}) 以完全了解 Provider/SubContext/Childs 何时重新渲染。
    • 我故意将其省略以表明更改主题提供程序值不会导致其子项重新渲染
    • 是的,很抱歉删除了我的评论(这是:“为什么不在孩子中使用 'theme' 变量)。但确切地说,在这种情况下......仍然在ThemeProvider 菜单值虽然没有发生在任何子项中重新渲染?这不是与您的 PS 评论相反吗?
    • 那是因为没有人订阅ThemeProvider,如果有任何组件订阅了,那么每当ThemeProvider重新渲染时,它都会重新渲染
    • 完美!谢谢美人
    猜你喜欢
    • 2020-08-10
    • 1970-01-01
    • 2020-06-13
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    相关资源
    最近更新 更多