React系列四:对象更新

React系列135328 阅读0

更新state中的对象

state 中可以保存任意类型的 JavaScript 值,包括对象。但是,你不应该直接修改存放在 React state 中的对象。相反,当你想要更新一个对象时,你需要创建一个新的对象(或者将其拷贝一份),然后将 state 更新为此对象。

在 React 中,状态是不可变的(immutable)。React 不会深入比较对象内部的属性变化,而是通过引用是否变化 来判断是否需要更新组件。

Vue(尤其是 Vue 3)使用 Proxy 实现响应式,它拦截对象属性的读写操作,能追踪字段级的变化。Vue 追踪的是属性访问和修改,不是对象的引用变化。

mutation:直接修改对象的某一个字段,如:obj.x = xxx

immutable:修改整个对象,如:obj = {...obj, x: xxx}

Vue 中可以直接使用 mutation,因为它内部通过响应式系统(如 Proxy)追踪属性变化;而 React 依赖 state 的不可变性(immutable),如果你直接修改原始对象(mutation),React 可能检测不到变化,从而不会重新渲染视图。

如果对象嵌套太深,修改起来就比较繁琐,这时候可以使用Immer 插件。当使用 Immer 时,类似 artwork.seen = nextSeen 这种会产生 mutation 的语法不会再有任何问题了。

更新 state 中的数组

数组是另外一种可以存储在 state 中的 JavaScript 对象,它虽然是可变的,但是却应该被视为不可变。同对象一样,当你想要更新存储于 state 中的数组时,你需要创建一个新的数组(或者创建一份已有数组的拷贝值),并使用新数组设置 state。

在 JavaScript 中,数组只是另一种对象。同对象一样,你需要将 React state 中的数组视为只读的。这意味着你不应该使用类似于 arr[0] = 'bird' 这样的方式来重新分配数组中的元素,也不应该使用会直接修改原始数组的方法,例如 push() 和 pop()。

相反,每次要更新一个数组时,你需要把一个新的数组传入 state 的 setting 方法中。为此,你可以通过使用像 filter() 和 map() 这样不会直接修改原始值的方法,从原始数组生成一个新的数组。然后你就可以将 state 设置为这个新生成的数组。

数组添加元素:

推荐:concat, [...arr]

不推荐:unshift, push

删除元素:

推荐:filter, slice

不推荐:pop, shift, splice

替换:

推荐:map

不推荐:splice, arr[i] = ...

排序:

推荐:复制数组

不推荐:reverse, sort

上面推荐的方法都是会返回一个新的数组,不推荐的方法都是会直接修改原数组的操作。

补充

slice 和 splice 的名字相似,但作用却迥然不同:

slice 让你可以拷贝数组或是数组的一部分。

splice 会直接修改 原始数组(插入或者删除元素)。

在 React 中,更多情况下你会使用 slice(没有 p !)

评论

发表评论