2022-11-17 useState与引用类型变量

浅拷贝引用类型变量引起的问题

 const outObj = { name: 'out' }
 const Demo = () => {
  const inObj = { name: 'in' }  
  const [state1,setState1] = useState(inObj)  
  const [state2,setState2] = useState(inObj)  
  const [state3,setState3] = useState(outObj)  

 useEffect(() => {
  setState1((oldValue) => {
    oldValue .age = 18
    return {...oldValue}
  })
  setState3((oldValue) => {
    oldValue .type = 'outchange'
    return {...oldValue}
  })
}, [])
useEffect(() => {
  console.log('改变\n')
  console.log(state1, '1')
  console.log(state2, '2')
  console.log(inObj, 'in')
  console.log(state3, '3')
  console.log(ouObj, 'out')
}, [state3])
...
}

得到的结果会有两次打印

改变
{ name: 'in', age: 18 } '1'
{ name: 'in', age: 18 } '2'
{ name: 'in', age: 18 } 'in'
{ name: 'out' } '3'
{ name: 'out'  } 'out'
改变
{ name: 'in', age: 18 } '1'
{ name: 'in', age: 18 } '2'
{ name: 'in' } 'in'
{ name: 'out', type: 'outchange' } '3'
{ name: 'out' , type: 'outchange' } 'out'

可以看到,第一次打印时机应为首次赋值给state3,此时inObj已经被修改了
而第二次打印则是改变state3,此时inObj又被初始化了
但改变了state3却引起外层outObj的改变

原因在于outObj是一个引用类型,useState只进行了浅拷贝,他们引用了同一个存储地址,因此修改后会造成相互影响。

结论

简单数据类型可以浅拷贝,复杂数据类型时使用深拷贝

相似方法

concat、slice、map、扩展运算符等都可能为浅拷贝

深拷贝的方法举例

  1. 不含方法的引用类型可以直接使用JSON转换大法
 JSON.parse(JSON.stringify(obj))
  1. 递归实现
    网上有很多方法,就不举例了

  2. 第三方库如lodash的cloneDeep(推荐使用,比网上找的递归更靠谱)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容