使用PureComponent改善React中的渲染性似乎是一种常见的技术。但是,使用具有子项作为道具的PureComponent时似乎并非如此。
class App extends React.PureComponent {
render() {
console.log('re-render')
return <div>{this.props.children}</div>
}
}
const render = () => {
ReactDOM.render(
<App>
<div />
</App>,
document.getElementById('app')
)
setTimeout(render, 1000)
}
render()
结果是控制台每1秒继续记录“重新渲染”。看起来孩子们(<div />
)是上面App
组件的唯一支柱并且永远不会改变,为什么App仍然会被重新渲染?
注意:如果有任何混淆,问题与上面PureComponent的SCU(shouldComponentUpdate)钩子返回 true 的原因相同,因为没有道具似乎改变了?
答案 0 :(得分:5)
这里发生的事情是你实际上正在调用ReactDOM.render()
,Page(或App,我认为你这里有一个拼写错误)组件将触发其render()
函数,无论使用{{1} }或Component
。
PureComponent可以帮助减少不必要的渲染的方式是当进行道具更改时,PureComponent将对PureComponent
和this.props
进行浅层比较以确定此PureComponent需要致电nextProps
。
我刚给你做了这个例子:
render()
注意以下几点:
class App extends React.PureComponent {
state = {value: 0}
componentDidMount() {
setInterval(() => {
this.setState({value: Math.random()})
}, 1000)
}
render() {
return (
<div>
<PureChild value="fixed value"/>
<ImpureChild value="fixed value"/>
</div>
)
}
}
class PureChild extends React.PureComponent {
render() {
console.log('rendering PureChild')
return <div>{this.props.value}</div>
}
}
class ImpureChild extends React.Component {
render() {
console.log('rendering ImpureChild')
return <div>{this.props.value}</div>
}
}
更改<App />
状态,因此会重新渲染,导致其所有子项重新渲染。value
是一个PureComponent,它对旧道具和传入的新道具进行浅层比较,并且通知两个道具都是<PureChild />
,因此它不会#39; t触发渲染!如果您运行此代码并打开控制台,您只能看到“渲染ImpureChild”#39;每1秒,但是会呈现PureChild&#39;只会出现一次。
答案 1 :(得分:4)
console.log(<div /> === <div />) // false
每次<App />
的重新呈现时,React.createElement(div, null)
都会创建新 React Element,因此this.props.children
将与nextProps.children
不同虽然它们在JSX中看起来一样。
实际上,真正的问题是,props.children
的引用(否则值是原始类型)在每次父渲染时都会发生变化,而React.PureComponent会通过引用来比较具有不变性的道具。
答案 2 :(得分:1)
现在根据ReactDOM
ReactDOM.render()
控制您传递的容器节点的内容 in。第一次调用时,里面的任何现有DOM元素都会被替换。 后来的调用使用React的DOM diffing算法进行有效的更新。
ReactDOM.render()
不会修改容器节点(仅修改 容器的孩子们)。可以插入一个 组件到现有DOM节点而不覆盖现有节点 孩子。
从第二次开始,ReactDOM只是使用它在其他地方使用的差异算法更新React组件,因此它不是ReactDOM,导致重新渲染。您可以通过在App Component中添加componentWillMount
方法来验证这一点,并检查它是否只被调用一次
现在来到PureComponent。文档说明了
React.PureComponent’s
shouldComponentUpdate()
只是浅析对象。如果这些包含复杂的数据结构,则可能会产生更深层次差异的假阴性。只有在您希望拥有简单的道具和状态
所以这是捕获,PureComponent可能会返回错误的负面以获得更深层次的差异。因此,当您尝试将this.props.children
与nextProps.children
进行比较以获得相等性时,您会发现它返回false
,因此会再次触发重新渲染
选中 CodeSandbox
答案 3 :(得分:0)
根据React.PureComponent的文档
1)。具有浅层属性和状态比较的PureComponent实现shouldComponentUpdate(),将检查是否需要重新渲染页面
2)。如果道具或状态中有复杂的对象,那么PureComponent将给出错误的肯定结果,必须运行强制更新
3)。更改父组件不会更新子组件,因此PureComponent的子组件也应该是PureComponent