为了账号安全,请及时绑定邮箱和手机立即绑定

跪求!react中直接修改state解构出来的值合理吗?怎么回事哈啊?

跪求!react中直接修改state解构出来的值合理吗?怎么回事哈啊?

开心每一天1111 2019-10-31 10:28:07
第一个栗子?state={name:'Sam'}fn(){const{data}=this.state;data.name='xiaobe';this.setState({data:{...data}})}没有出现警告,且能实现效果,但这样的做法合理吗?第二个栗子?:使用了lodash/find,重新赋值了一个新的数组,但是原数组依旧被更改了,为什么?importfindfrom'lodash/find';state={data:[{id:1,name:'xiaobe'},{id:2,name:'Sam'}]}fn(){const{data}=this.state;constnewData=[...data];console.log('修改前data',data);constnewItem=find(newData,{id:1})||{};console.log('修改前newItem',newItem);if(Object.keys(newItem).length){newItem.name='new-xiaobe';}console.log('修改后newItem',newItem);this.setState({data:[...newData],},()=>{console.log('修改后data',data);},);}发现,修改前data里第一条name已经从xiaobe变成了new-xiaobe,请问为什么?
查看完整描述

2 回答

?
白板的微信

TA贡献1883条经验 获得超3个赞

在回答问题之前,先补充以下几个知识点:
栈内存和堆内存。基本数据类型的数据是存在栈内存的,而引用类型的数据则是存在堆内存的,在栈内存里面存放的实际是数据在堆内存中的内存地址。
浅拷贝和深拷贝。浅拷贝仅仅是复制了数据在栈内存中的内存地址,而深拷贝指在计算机中开辟了一块新的内存地址用于存放复制的对象。
第一个栗子:首先这样子的写法是没有问题,react调度的时候会判断oldData和newData是否相等,不相等时则更新视图,引用类型之间的比较实际就是内存地址的比较,如果内存地址是一样则判断结果为true,不一样则判断结果为false。这里的{...data},相当于重新开辟了内存地址,newData相比较oldData,内存地址发生了改变,那么react便会知道其发生了改变,然后去更新视图。但这种写法并不是最好的,因为毕竟是对原数据做了修改,而this.setState又是异步的,如果在this.setState之后紧跟着依据data又做了其他相应的操作,那么就会有问题。我个人推荐的写法应该是这样子的:
state={
name:'Sam'
}
fn(){
const{data}=this.state;
this.setState({
data:{...data,name:'xiaobe'}
})
}
第二个栗子:理解这个问题的核心就是得了解[...data]到底干了啥?下面以你提供的数据来解释以下:
为了方便理解,我改造一下data。
consta={
id:1,
name:'xiaobe'
}
constb={
id:2,
name:'Sam'
}
constdata=[a,b]
[...data]的流程如下:
constnewData=[]//newArray()
newData.push(a)
newData.push(b)
通过上面的代码,我们发现如果直接判断newData===data,结果一定为false,因为newData的内存地址和data的不一致。但是如果你判断newData[0]===data[0]以及newData[1]===data[1],那结果变为true,子项的内存地址并没有发生变化。当你修改第一项的name值之后,便会影响到data和newData,因为这个子项被data和newData都引用了。
                            
查看完整回答
反对 回复 2019-10-31
  • 2 回答
  • 0 关注
  • 449 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信