反应上下文重新渲染提供者的每个孩子?
Posted
技术标签:
【中文标题】反应上下文重新渲染提供者的每个孩子?【英文标题】:react context rerenders every child of Provider? 【发布时间】:2020-08-19 07:08:34 【问题描述】: import React, useReducer, useEffect ,Component from "react";
import ReactDOM from "react-dom";
const AppContext = React.createContext();
import React from "react";
const withRandomColors = WrappedComponent =>
return class RandomColors extends React.Component
constructor()
super();
this.randomColors = [
"red",
"blue",
"green",
"cyan",
"lavender",
"skyblue",
"orange",
"pink",
"yellow"
];
getRandomColors()
const num = Math.floor(Math.random() * 10) % 9;
return this.randomColors[num];
render()
console.log("Rerendering wrapper Component");
return <WrappedComponent randomColor=this.getRandomColors() />;
;
;
class Number extends React.Component
constructor(props)
super(props);
componentDidMount()
render()
console.log("rendering Number Component");
return (
<AppContext.Consumer>
( number ) =>
return (
<div style= backgroundColor: `$this.props.randomColor` >
number <br />
</div>
);
</AppContext.Consumer>
);
class Text extends React.Component
constructor(props)
super(props);
render()
console.log("rendering Text Component");
return (
<AppContext.Consumer>
( text ) => (
<div style= backgroundColor: `$this.props.randomColor` >
text <br />
</div>
)
</AppContext.Consumer>
);
const WrappedText=withRandomColors(Text);
const WrappedNumber=withRandomColors(Number);
class App extends Component
constructor()
super();
this.state =
number: Math.random() * 100,
text: "testing context api"
;
updateNumber = () =>
const randomNumber = Math.random() * 100;
this.setState( number: randomNumber );
;
render()
console.log("rendering app")
return (
<AppContext.Provider value=this.state>
<div>
<h1>Welcome to React</h1>
<WrappedNumber />
<WrappedText />
<button onClick=this.updateNumber>Change Number </button>
</div>
</AppContext.Provider>
);
ReactDOM.render(
<App />,
mountNode
);
当点击 ChangeNumber 按钮时控制台显示
rendering app
Rerendering wrapper Component
Rerendering Number Component
Rerendering wrapper Component
Rerendering Text Component
数字和文本的背景颜色会发生变化。
React 上下文应该只为提供者重新呈现消费者,对吗?为什么要重新渲染 Provider 的所有子节点?
我希望只有数字更改保持数字和文本的背景颜色相同,并在单击更改数字按钮后低于控制台输出,因为只有消费者应该重新呈现文本和数字组件。
rendering app
我错过了什么?
我从sandbox获取代码
【问题讨论】:
【参考方案1】:WrappedNumber
和 WrappedText
会在您更新 App 组件中的状态时重新渲染,因为在 Virtual DOM 中它们与 Provider 处于相同的层次结构中,并且当父组件更新时,子组件也会更新。
为了避免它们重新渲染,您可以将它们作为 App 的子级提供
class App extends Component
constructor()
super();
this.state =
number: Math.random() * 100,
text: "testing context api"
;
updateNumber = () =>
const randomNumber = Math.random() * 100;
this.setState( number: randomNumber );
;
render()
console.log("rendering app")
return (
<AppContext.Provider value=this.state>
<div>
<h1>Welcome to React</h1>
this.props.children
<button onClick=this.updateNumber>Change Number </button>
</div>
</AppContext.Provider>
);
ReactDOM.render(
<App >
<WrappedNumber />
<WrappedText />
</App>,
mountNode
);
【讨论】:
好的。但是在创建 App 节点时我没有在运行时提供 WrappedText 和 WrappedNumber 儿童,而是在 App 的 render 方法中对它们进行了硬编码,但是两者都产生相同的结果,对吧?两者在反应如何处理这方面有什么区别吗? 正如我所说,不同之处在于如何使用虚拟 DOM 处理它们。当组件由于 state 或 props 改变而重新渲染时,任何直接在其 render 方法中重新渲染的组件都会被重新渲染。然而,上下文变化是专门向消费者传播的。当您将组件移出到 App 的父级并将它们呈现为子道具时,当 App 由于状态更改而重新渲染时,它们不会重新渲染以上是关于反应上下文重新渲染提供者的每个孩子?的主要内容,如果未能解决你的问题,请参考以下文章
从消费者 componentDidMount 更新反应上下文会导致无限重新渲染