componentDidUpdate有时无法比较出前一个状态和当前状态的不同

文章前先了解如何在JavaScript里进行深拷贝,深拷贝函数移步https://blog.csdn.net/ZxqSoftWare/article/details/88950228

 

一、深度拷贝

为什么要深拷贝呢?这里举几个例子:

1、一般变量和数组变量:

let a = 0;
> a = 0

let b = a;
> a = 0, b = 0

a = 1;
> a = 1, b = 0

a = [1,2,3]
> a = [1,2,3]

b = a
> a = [1,2,3], b = [1,2,3]

let c = [1,a,a]
> c = [1,[1,2,3],[1,2,3]]

a = [4,5,6]
> a = [4,5,6], b = [1,2,3], c = [1,[1,2,3],[1,2,3]]

一般变量是数或字符串,直接赋值确实是新建了一个变量,数组也是,这样不会带来任何问题,甚至可以数组嵌套数组,但是当涉及到复杂对象时(数组是Array类型,也继承了Object,但是组成比较简单,就称之为简单对象吧,与之相对的,有较多属性,不只是以序号为索引的对象,就称它们为复杂对象吧),情况有了极大的变化:

 

2、字典和继承自Object的其他对象

字典是非常有用的一个类型,和在python里面自成一个类的字典基本上一样,除了在python里面额外可以用a = dict()定义外几乎一样,具体区别就不在这里赘述。直接上代码:

let a = {
    name: 'hello',
    age: 20
};
> a = {name: 'hello', age:20}

let b = a;
> a = {name: 'hello', age:20}, b = {name: 'hello', age:20}

a.age = 40;
> a = {name: 'hello', age:40}, b = {name: 'hello', age:40}

地址引用的不方便立马显示了出来,一个字典变了,另一个会跟着变,其他继承自Object的对象也都一样,那么下面的情况呢?

let a ={
    name: 'hello',
    age: 20
}
> a = {name: 'hello', age:20}

let b = [1,2,3,a]
> a = {name: 'hello', age:20}, b = [1,2,3,{name: 'hello', age:20}]

let c = {
    guest: [a, a, a, a, a, a, a, a, a, a],
    totalNum: 10
}
> // 太多了就不贴出来了,大家自行实验

a.age = 40;
> //所有引用了 a 的地方都跟着变了

数组中嵌套字典,字典中嵌套字典,以及各种各样的复杂用法,单纯的引用是无法用在生产环境中的,这就体现出了深拷贝的重要性:我们需要一个新的对象,完整复制另一个对象的所有属性和值,并且可以修改,我用文章开头给大家的链接里面的函数arrayDeepCopy(obj)来深拷贝一个对象,至少不会轻易带来引用带来的尴尬问题。

 

二、componentDidUpdate无法做比较?

react里面的内建函数componentDidUpdate(prevProps, prevState)提供了一种可能,让开发者在等界面完全render后进行一些请求或者其他操作,比如setState(),大多数情况下,为了避免循环调用这个函数,官方要求在函数内加一行判断,以确保不会陷入无限循环,例:

componentDidUpdate(prevProps, prevState){
    if ( prevState.flag !== this.state.flag ){
        // fetchUserData(userID);    // 网络请求获取用户信息
    }
}

但是一旦要比较的部分是对象,最简单就比如是一个字典,会发现这个方法失效了。因为每次比较时的结果都是一样的(关于比较对象是否相等,请参阅我的另一篇博客https://blog.csdn.net/ZxqSoftWare/article/details/88553965),是因为它们比较的是同一个地址上的对象,不管怎么神通广大肯定都是相同的,这时候要么想办法设计一个单字符串变量或者bool变量,要么在进入这个函数前暂存这个对象的深度副本,比较时比较这个副本和实际的值。参考代码如下:

constructor(props){
    super(props);
    this.tmpData={};
    // ... Other code
}

produce(data){
    this.tmpData = arrayDeepCopy(data)   // 假设生产出来的数据是{a: '123', b:{c: '234'}}
    this.setState({data: data})
}

componentDidUpdate(prevProps, prevState){
    if ( !arrayIdentical(this.tmpData, this.state.data) ){
        // fetchUserData(userID)
    }
}

不敢说这个方法的效率如何,但是在项目中是挺有用的,

如果有更有效的方法,还请大佬们不吝教导,不到之处,请大佬们使劲喷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值