【问题标题】:React Context Provider all children re renderingReact Context Provider 所有子级重新渲染
【发布时间】:2021-04-14 17:40:33
【问题描述】:

有人可以向我解释为什么下一个代码会重新渲染来自提供者的所有子组件

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

const ThemeContext = createContext();

const App = () => {
    const [theme, setTheme] = useState(false);
    console.log("App running");
    return (
        <ThemeContext.Provider value={{ theme, setTheme }} children={<Child1 />} />
    );
};

const Child1 = () => {
    console.log("Child1 running");
    return (
        <div className="child1">
            <Child2 />
        </div>
    );
};

const Child2 = () => {
    console.log("Child2 running");
    return (
        <div className="child2">
            <Child3 />
        </div>
    );
};

const Child3 = () => {
    const { theme, setTheme } = useContext(ThemeContext);
    console.log("Child3 running");
    return (
        <div className="child3">
            <p>{theme ? "dark" : "light"}</p>
            <button onClick={() => setTheme(!theme)}>Change theme</button>
        </div>
    );
};

export default App;

控制台每次点击按钮,所有组件都会重新渲染

App running
Child1 running
Child2 running
Child3 running
App running
Child1 running
Child2 running
Child3 running

但是如果上下文提供者被包装在一个组件中,如下所示

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

const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState(false);
    console.log("ThemeProvider running");
    return (
        <ThemeContext.Provider value={{ theme, setTheme }} children={children} />
    );
};

const App = () => {
    console.log("App running");
    return <ThemeProvider children={<Child1 />} />;
};

const Child1 = () => {
    console.log("Child1 running");
    return (
        <div className="child1">
            <Child2 />
        </div>
    );
};

const Child2 = () => {
    console.log("Child2 running");
    return (
        <div className="child2">
            <Child3 />
        </div>
    );
};

const Child3 = () => {
    const { theme, setTheme } = useContext(ThemeContext);
    console.log("Child3 running");
    return (
        <div className="child3">
            <p>{theme ? "dark" : "light"}</p>
            <button onClick={() => setTheme(!theme)}>Change theme</button>
        </div>
    );
};

export default App;

点击按钮时的控制台

ThemeProvider running
Child3 running
ThemeProvider running
Child3 running
ThemeProvider running
Child3 running

只有使用上下文的组件(和组件上下文提供者)才会重新渲染

react 究竟是如何处理这种情况的

编辑:

react 版本是 17.0.1 顺便说一句

【问题讨论】:

    标签: javascript reactjs react-context


    【解决方案1】:

    发生这种情况是因为 &lt;Context.Provider&gt; 在其 children prop不与之前的 children prop 共享引用相等时重新渲染。

    在第一个示例中,每次重新渲染 App 时,都会创建一个 new Child1 React 元素。

    基本上就像你在做这样的事情:

    const App = () => {
      const [theme, setTheme] = useState(false);
      console.log("App running");
      return React.createElement(ThemeContext.Provider, {
        value: {
          theme: theme,
          setTheme: setTheme
        },
        children: React.createElement(Child1, null) <= Notice how the children prop is new with every re-render
      });
    };
    

    最终会重新渲染 Child1Child2Child3


    在第二个示例中,React 元素 Child1App 内创建一次,然后将其传递给 ThemeProvider,这意味着在 ThemeProvider 内您实际上是在引用 相同 React 元素,并且不会在每次重新渲染时创建一个新元素,因此在这种情况下,只有关联的消费者组件 (Child3) 会重新渲染。

    Good read about why this happens

    【讨论】:

    • 原始函数 createElement 比语法糖更清晰,至少对我来说是这样
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 2019-03-05
    相关资源
    最近更新 更多