为什么React状态中数组的pop()或push()方法可以工作

4
const { items } = this.state;
this.setState({ 
  items: this.state.items.slice(0, this.state.items.length - 1)
});

我知道上面的代码在React中可以很好地工作。

然而,

const { items } = this.state;
items.pop();
this.setState({ items });

如果有一个由this.state.items渲染的列表(比如<div className="list">{this.state.items}</div>),我不明白为什么dom仍然会更新。

我很困惑items.pop()已经改变了原来的状态,为什么下一个状态的items等于原来状态的items,但是dom仍然可以更新。


.slice() 也可以使用,它有默认参数。 - Jonas Wilms
5个回答

2
下一个状态的项目与原始状态的项目不相等,因为您正在使用数组可变方法(更多信息请参见MDN Mutable Methods)。此pop方法直接修改数组,而不像其他方法(map,filter不可变方法)生成副本。

2

调用 setState 将总是重新渲染组件。无论状态是否实际更改都是如此。要更改该行为,您必须实现自定义 shouldComponentUpdate


我知道setState会调用render()方法,如果shouldComponentUpdate()返回true,但我不知道为什么dom会改变,因为我认为原始状态等于下一个状态。它们都从项目列表中弹出一个元素。 - lazysheep
@lazysheep 什么意思?如果调用render函数,内容会改变吗? - Jonas Wilms
我在我的问题中漏掉了一个要点,那就是由items数组呈现的列表。 - lazysheep
@lazysheep 为什么这很重要?无论子组件在做什么,该组件都会重新渲染。 - Jonas Wilms

2
如果我理解正确的话,您想知道为什么如果您的变异也应用于旧状态,DOM会发生更改。您认为“如果我改变旧状态,则两个状态都指向相同的数组或对象引用”。是的,您在这里并没有创建全新的数组/对象,但我认为React不会查找引用

React查找许多内容,但在您的情况下,它通过比较数组的元素和子元素来查找DOM更改。旧DOM比新DOM多一个元素。因此,它销毁旧的并安装新的。


非常感谢,我刚刚自己解决了问题,而且你理解我的意思。 - lazysheep
不客气 :) 无论如何,最好选择一个答案来接受并关闭你的问题。你可以自己提供一个答案,解释你是如何想出来的并说明它是如何工作的。然后,如果你不想接受其他提供的答案,你可以接受你自己的答案。 - devserkan

0

你正在使用React.Component而不是React.PureComponent

默认情况下,如果使用setState或者父组件重新渲染,甚至如果props或state没有改变,React也会重新渲染。但是,PureComponent在shouldComponentUpdate中进行相等性检查,因此只有当所有props和state通过严格相等性检查===时(因此是“pure”),它才不会重新渲染。


0

你的问题是为什么第二个代码块会更新你的组件,即使组件状态没有改变?你贴出的两个代码块都会导致组件更新,因为你调用了setState()。如果你查看setState()的文档,它说“除非shouldComponentUpdate()返回false,否则setState()将始终导致重新渲染”。如果你不想让组件更新,那就不要调用setState()。


我知道 render 方法会被调用,但我不知道为什么在 items 渲染列表时 dom 会被更新。因为我认为前一个和后一个元素都从 items 中弹出了一个元素,所以它们是相等的。 - lazysheep

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