Mag*_*nus 8 javascript reactjs
在另一StackOverflow上后,谢霆锋让我了解到,一个Context.Provider重新呈现其子Context.Consumer组件时的上下文值的Provider规定变化。
官方文件进一步证实了这一点:
每当 Provider 的 value 属性发生变化时,所有作为 Provider 后代的消费者都会重新渲染。
Nicholas 还帮助我理解了 a Providerwill 知道上下文值是否发生变化的唯一方法,是它的封闭组件是否重新渲染。
总之:
ProvidersConsumers每当上下文值更改时更新它Provider重新渲染周围的封闭函数时发生Provider无论如何,这会导致及其所有后代重新渲染因此,上面(1)中的特征似乎是多余的。如果Provider仅Consumers在其封闭组件重新渲染时才更新,并且仅在父级重新渲染时发现上下文值更新,则不需要具有允许在上下文值更改时Provider更新的功能。Consumers
我在这里缺少什么?
编辑
尼古拉斯还在评论中说:
由于与通过上下文提供的价值无关的事情,应用程序可以(可以想象)重新渲染。如果发生这种情况,您不希望消费者重新渲染。为此,您需要之前的值和之后的值才能通过 === 检查。如果您提供一个对象,这意味着您不能在 App 的 render 方法中创建一个全新的对象,否则最终会不必要地重新渲染消费者。
但是,我的印象是,当父级重新渲染时,其所有子级也将重新渲染。因此,===上面提到的检查无济于事,即孩子们无论如何都会重新渲染。
- 这会导致 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";
}
Run Code Online (Sandbox Code Playgroud)
在初始安装时,所有这 3 个都会渲染。但是,如果顶层组件更新其状态,则只有顶层组件才会重新渲染。中层组件将由于其 shouldComponentUpdate 而被跳过,然后底层组件甚至不会被考虑。(请参阅下面的实时代码片段 - 更好地在全页模式下运行)
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";
}
Run Code Online (Sandbox Code Playgroud)
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"));Run Code Online (Sandbox Code Playgroud)
现在,我们将上下文提供者添加到顶级组件,并将上下文使用者添加到底层组件。在初始安装时,它们将再次全部渲染。如果顶层组件更新其状态,它将重新渲染。由于其 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";
}
Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
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";
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1953 次 |
| 最近记录: |