In 另一篇 StackOverflow 帖子,尼古拉斯帮助我理解了Context.Provider
重新呈现其后代Context.Consumer
组件时上下文值 the Provider
提供更改。
这一点得到了进一步证实官方文档:
作为提供者后代的所有消费者都将重新渲染
每当提供者的价值支柱发生变化时。
尼古拉斯还帮助我明白,唯一的方法是Provider
就会知道如果上下文值已更改,即其封闭组件是否重新呈现。
总之:
-
Providers
更新其Consumers
每当上下文值 changes
- 仅当围绕函数的封闭函数时,才会发生这种情况
Provider
重新渲染
- 这导致了
Provider
无论如何它的所有后代都会重新渲染
因此,上面(1)中的特征似乎是多余的。如果Provider
永远只更新Consumers
当其封闭组件重新渲染时,并发现上下文值更新只能在父级重新渲染时发生,不需要具有允许Provider
更新Consumers
当。。。的时候上下文值变化。
我在这里缺少什么?
EDIT
尼古拉斯还在评论中说:
应用程序可以(可以想象)由于无关的事情而重新渲染
它通过上下文提供的价值。如果发生这种情况,您不希望
消费者重新渲染。为此,您需要该值
before 和 after 的值通过 === 检查。如果您提供
对象,这意味着你不能在App的渲染中创建一个全新的对象
方法,否则您最终将不必要地重新呈现消费者。
然而,我的印象是,当父母重新渲染时,all它的子级也将重新渲染。就这样===
上面提到的检查没有帮助,即孩子们无论如何都会重新渲染。
- 这会导致 Provider 及其所有后代重新渲染
虽然这是默认行为,但实际上,通常会更改此行为以提高性能。纯组件、实现 shouldComponentUpdate 的组件或使用 React.memo 的组件将导致重新渲染在遍历整个树之前停止。
例如:假设有一个具有某种状态的顶级组件,它呈现一个具有以下状态的中级组件:shouldComponentUpdate() { return false; }
,它呈现底层组件。
function TopLevelComponent() {
const [topLevelState, setTopLevelState] = useState(0);
return (
<>
<h1>Top Level Component</h1>
<button onClick={setTopLevelState( v => v + 1)}>Update Top Level State</button>
<MidLevelComponent />
</>
);
}
class MidLevelComponent extends React.Component {
shouldComponentUpdate() {
return false; // <= This guy will prevent re-rendering of this component and everything nested under it
}
render() {
return (
<>
<h2>Mid Level Component</h2>
<BottomLevelComponent />
</>
);
}
}
function BottomLevelComponent() {
return "Bottom Level";
}
在初始安装时,所有这 3 个都会渲染。但是,如果顶层组件更新其状态,则只有顶层组件才会重新渲染。中层组件将由于其 shouldComponentUpdate 而被跳过,然后底层组件甚至不会被考虑。(请参阅下面的实时代码片段 - 更好地在全页模式下运行)
console.log("--- Initial Render");
function BottomLevelComponent() {
console.log("BottomLevelComponent() => renders");
return "Bottom Level";
}
class MidLevelComponent extends React.Component {
shouldComponentUpdate() {
return false;
}
render() {
console.log("MidLevelComponent() => renders");
return (
<div>
<h2>Mid Level Component</h2>
<BottomLevelComponent />
</div>
);
}
}
function TopLevelComponent() {
console.log("TopLevelComponent() => renders");
const [topLevelState, setTopLevelState] = React.useState(0);
const handleTopLevelUpdate = () => {
console.log("--- Updating Top Level State");
setTopLevelState((v) => v + 1);
};
return (
<div>
<h1>Top Level Component</h1>
<button onClick={handleTopLevelUpdate}>Update Top Level State</button>
<MidLevelComponent />
</div>
);
}
ReactDOM.render(<TopLevelComponent />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>
现在,我们将上下文提供者添加到顶级组件,并将上下文使用者添加到底层组件。在初始安装时,它们将再次全部渲染。如果顶层组件更新其状态,它将重新渲染。由于其 shouldComponentUpdate,中级组件仍将跳过其渲染。但只要上下文值发生变化,底层组件就会重新渲染,即使其父级组件已退出。这就是该简介中提到的功能。
const TopLevelContext = React.createContext();
export default function TopLevelComponent() {
const [topLevelState, setTopLevelState] = useState(0);
return (
<TopLevelContext.Provider value={{ topLevelState }}>
<h1 onClick={setTopLevelState((v) => v + 1)}>Top Level Component</h1>
<MidLevelComponent />
</TopLevelContext.Provider>
);
}
class MidLevelComponent extends React.Component {
shouldComponentUpdate() {
return false; // <= Will prevent rendering of this Component and everything nested under it, but...
}
render() {
return (
<>
<h2>Mid Level Component</h2>
<BottomLevelComponent />
</>
);
}
}
function BottomLevelComponent() {
React.useContext(TopLevelContext); // <= ...this will override the shouldComponentUpdate of the parent and trigger a re-render when the Context provider value changes
return "Bottom Level";
}
console.log("--- Initial Render");
const TopLevelContext = React.createContext();
function BottomLevelComponent() {
React.useContext(TopLevelContext);
console.log("BottomLevelComponent() => renders");
return "Bottom Level";
}
class MidLevelComponent extends React.Component {
shouldComponentUpdate() {
return false;
}
render() {
console.log("MidLevelComponent() => renders");
return (
<div>
<h2>Mid Level Component</h2>
<BottomLevelComponent />
</div>
);
}
}
function TopLevelComponent() {
console.log("TopLevelComponent() => renders");
const [topLevelState, setTopLevelState] = React.useState(0);
const handleTopLevelUpdate = () => {
console.log("--- Updating Top Level State");
setTopLevelState((v) => v + 1);
};
return (
<TopLevelContext.Provider value={{ topLevelState }}>
<h1>Top Level Component</h1>
<button onClick={handleTopLevelUpdate}>Update Top Level State</button>
<MidLevelComponent />
</TopLevelContext.Provider>
);
}
ReactDOM.render(<TopLevelComponent />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)