React系列——用简单的例子掌握不可突变数据结构

数据结构对react的影响

开发React的时候,我们可能会发现有时候state设置了一个新值,但是它并没有执行重新渲染。然后就疯狂找bug,却很难发现问题是什么。
这是因为你在setState的时候,对原数据结构做了修改,造成原数据突变了。

什么是数据结构突变

举个很简单的例子🌰

1、声明并初始化一个数组a

var a = [1]

2、现在我们想将数组a的值改一下,比如增加一个元素2,你会想到很多种方法,但是如果你用了push,就会造成原数据突变。

push:
下面这个例子展示了数组a的变化。而react中,开发者不应该这样去修改数据。

var a = [1]
a.push(2)
console.log(a) // [1, 2]

什么是数据结构不突变

1、我们仍旧声明并定于一个数组b

var b = [1]

2、当我们给数组b增加一个元素2,但是又不想改变数组b的值,而是通过一些方法生成一个新的数组来保存数据。

concat:
使用concat来给数组增加元素,会返回新的数组,所以使用变量c来保存。而原数组b的值没有改变,这就是b的数据结构不突变。

var b = [1]
var c = b.concat(2)
console.log(b) // [1]
console.log(c) // [1, 2]

react中的数据结构突变解决方案

在state中定义的数据结构,为了防止原始数据结构的突变,可以采取很多办法,当然,你可以用immutable.js来帮你完成这件事情,也可以自己从写法上避免。

1、setState或者reducer中应该return一个新的对象,而不是原对象,这就要求你在使用js原生操作对象时避免使用修改原对象的函数,比如push。

2、但有时候你又必须使用push等函数,则使用es6的扩展运算符(...)或者Object.assign()拷贝一个新的对象。

state = {
    a: [1]
}
componentDidMount() {
    const { a } = this.state
    a.push(2)
    this.setState(() => ({a: a, ...this.state}))
}

3、使用Object.freeze冻结原始对象,防止你使用了不当的函数修改原始数据。

state = {
    a: {b: 1}
}
componentDidMount() {
    var state = {
        a: {b: 1}
    }
    const x = Object.freeze(state.a) //冻结原始对象a
    x.c = 2 //尝试给冻结后的对象增加属性
    console.log(x) //发现原始数据不被改变
    
    const newData = {c: 2} //新建一个对象保存需要增加的属性
    console.log({...x, ...newData}) //使用扩展运算拷贝原始对象,并合并成一个新的对象。
}

总结

如果你担心数据不可控,容易造成突变的情况,则可以使用immutable来彻底解决问题,其他情况下,则不需要担心,如果你懂了什么时候数据会突变,学会采用原生js的方法一样可以避免它。

相关文章
相关标签/搜索
每日一句
    每一个你不满意的现在,都有一个你没有努力的曾经。
公众号推荐
   一个健康类的公众号,欢迎关注
小青桔健康