PureComponent是如何工作的?

3
我的理解是PureComponent利用shouldComponentUpdate()方法,对状态和属性进行浅比较,但我创建了一个小例子,其操作方式与我的预期不同。
该示例应用程序显示人员列表。每个列表项都可以更改其名称。请尝试并检查此处的代码。
在父组件中,我有一个如下所示的方法:
  updateName(id, newName) {
    const { people } = this.state
    const idx = people.findIndex(person => person.id === id)

    people[idx].name = newName
    this.setState({ people })
  } 

我将要传回到 setState 的对象与之前的对象具有相同的引用。在这种情况下,如果进行浅比较,该组件不应更新,对吗?

其次,另一个不清楚的部分是,我将子组件 Person 从 PureComponent 更改为 Component,但仍然获得了只有更新的子组件重新渲染的好处(如果您想检查,我对每个子组件呈现都进行了控制台记录)。显然,这是React内部决定子组件是否应更新的事情,但我认为如果组件重新呈现,它会重新呈现所有内容。


请返回仅翻译的文本: https://codeburst.io/when-to-use-component-or-purecomponent-a60cfad01a81。 https://habrahabr.ru/company/redmadrobot/blog/318222/ - zloctb
1个回答

2
如果这个组件正在进行浅比较,那么它不应该更新,是的。而且它没有更新。你可以看到,在初始渲染后,App组件的render()方法不会再次被调用。这意味着浅比较按照你的期望工作,并且组件(正确地)不会更新。我认为让你感到困惑的部分是Person.prototype.handleSubmit()中的这行代码:
this.setState({ value: '' })

由于oldState.value !== newState.value,这将触发修改的Person组件重新渲染,无论Person是否为PureComponent

如果您删除此行,则会发现没有任何更新(这是您预期的行为)。

显然,这是React在内部决定子级是否应该更新的事情。

不,子级正在设置自己的状态。父子关系在这里是无关紧要的。React将直接更新子级。

将来,您应该尝试隔离您的测试。导致混淆的原因是您依赖render()方法来确定子级是否收到了新的props。但是当子级收到新props并且子级设置新状态时,将调用render()方法。

对于这种情况的更好的测试将是检查是否调用了componentWillReceiveProps(),从而消除state的影响:

componentWillReceiveProps(newProps) {
    console.log('receiving props', newProps)
}

如果你将这个代码插入到Person组件中,你会发现它并没有被调用。这正是你所期望的。
简而言之,React.PureComponent的工作方式与你想象的完全一样。

非常好而且详细的回答@bowheart。一个快速的澄清,如果我在handleSubmit中保留行this.setState({ value: '' })并像您上面所述添加了componentWillReceiveProps方法,则当我提交时用户的名称会更新。您是说状态更改告诉子元素的渲染函数进行更新,因此即使未触发componentWillReceiveProps以通知子组件已更新,它也会检查来自props的更新名称。基本上,引用反映了更改但没有通知组件。 - captDaylight
1
@captDaylight 哦,好发现。你是对的。即使该对象不作为新属性再次传递,它仍然是同一个对象。该引用对象正在被改变。当 render() 从该对象读取 name 属性时,它将会是不同的。这种隐式状态依赖关系是 React 社区坚持保持数据不可变性的原因。 - bowheart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接