can someone explain to me why the next code re renders all children ponents from the provider
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;
console everytime button is clicked, all ponents re rendering
App running
Child1 running
Child2 running
Child3 running
App running
Child1 running
Child2 running
Child3 running
but if context provider is wrapped in a ponent as follows
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;
console when button is clicked
ThemeProvider running
Child3 running
ThemeProvider running
Child3 running
ThemeProvider running
Child3 running
only the ponent consuming the context (and the ponent context provider) are re rendering
how exactly react manages this situation
EDIT:
react version is 17.0.1 btw
can someone explain to me why the next code re renders all children ponents from the provider
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;
console everytime button is clicked, all ponents re rendering
App running
Child1 running
Child2 running
Child3 running
App running
Child1 running
Child2 running
Child3 running
but if context provider is wrapped in a ponent as follows
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;
console when button is clicked
ThemeProvider running
Child3 running
ThemeProvider running
Child3 running
ThemeProvider running
Child3 running
only the ponent consuming the context (and the ponent context provider) are re rendering
how exactly react manages this situation
EDIT:
react version is 17.0.1 btw
Share Improve this question edited Jan 9, 2021 at 3:08 William Estrada asked Jan 9, 2021 at 2:22 William EstradaWilliam Estrada 1411 silver badge9 bronze badges2 Answers
Reset to default 6This happens because <Context.Provider>
re-renders when its children prop does not share reference equality with the previous children prop.
In the first example, every time App
is re-rendered, a new Child1
React element is created.
It's basically like if you were doing something like this:
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
});
};
which eventually re-renders Child1
, Child2
and Child3
.
In the second example, the React element Child1
is created once inside App
, and it's passed down to ThemeProvider
, which means that inside ThemeProvider
you are actually referencing the same React element, and not creating a new one with every re-render, so in this case only the associated consumer ponent (Child3
) will re-render.
const App = ({ children }) => {
const [theme, setTheme] = useState(false);
console.log("App running");
return React.createElement(ThemeContext.Provider, {
value: {
theme: theme,
setTheme: setTheme
},
children: children
});
};
Good read about why this happens
In the first example the useState hook is being called in App which causes it to rebuild the children prop () as a new element that's being passed to the Provider, rebuilding subtree. In your second example, App is not being rerendered (as useState is moved down) so the children () prop passed to the Provider does not change and the subtree is not rebuilt.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744235051a4564433.html
评论列表(0条)