mutation概念与Immer库的使用

本文介绍了React中关于state的只读性原则,如何通过展开语法复制对象和多层嵌套对象,以及如何避免mutation引发的问题,最后推荐了Immer库用于处理复杂状态更新,包括对象和数组的高效管理。
摘要由CSDN通过智能技术生成

1 mutation概念

const [user, setUser] = useState( {id: '123', name: '张三'} );

如上方示例,在react引用state时,无论state的值是什么类型,都要将存在state的js值视为只读的, 也就是不允许修改,如果直接修改了state的值(例如user.name = '李四'),这个操作就制造了一个mutation。在react使用state时,要遵循state的值是不可变的原则

2 原理理解

直接修改state对象的某个值,并没有调用state的更新函数setXXX,因此react无法识别修改的内容,不会触发重新渲染。为了避免制造mutation而造成的无法重新渲染问题,需要调用setXXX替换原有的值,包括对象。例如setUser({ id: '123', name: '李四' })。

3 通过展开语法复制对象

通过setXXX替换对象需要将对象原有的所有属性都写一遍,如果对象的属性特别多,就可以使用展开语法来实现,代码更简洁,例如:setUser({ ...user, name: '李四' })

理解:...user语法复制了user对象的所有属性,但是name属性使用 '李四' 覆盖

4 展开语法复制多层嵌套对象

嵌套对象理解

对象实际没有嵌套之说,他们都是互相独立的,所谓的对象嵌套,只不过是属性的指向而已。

例如:const user = { name: '张三' , size: { weight: 78, height: 180 } }

实际上看到的是两个不同的对象:user = { name: '张三' , size: sizeObj },sizeObj = { weight: 78, height: 180 }

复制多层嵌套对象:

按照上面展开语法的方式,复制对象可能要写成:

setUser({

         ...user, // 复制其他字段

         name: '李四', // 替换name字段

        size: {

                ... user.size, // 复制其他size被嵌套对象的字段

                height: 182 // 替换height字段

        }

})

如果嵌套较深或者特别多的情况下,代码看起来也不简洁,这时候,就可以使用Immer库。

5 Immer库的使用

使用方式

(1)安装依赖:npm install use-immer

(2)引入import { useImmer } from 'use-immer',替换掉import { useState } from 'react'

(3)自定义Immer(替换原自定义state):const [user, updateUser] = useImmer( {id: '123', name: '张三', size: { weight: 78, height: 180} } );

(4)修改对象属性写法:

updateUser(draft => {

        draft.name = '李四';

        draft.size.height = 182;

})

理解:

Immer提供了一个draft特殊类型的对象,会记录你用它进行的操作。这样用Immer看似直接修改了对象的属性,实际上Immer 会弄清楚draft对象的哪些部分被改变了,并会依照你的修改创建出一个全新的对象。

6 展开语法更新数组

state数组类型值的mutation:

state更新数组与对象一样,也要视为只读(不建议使用push、pop、splice等会改变原数组的方法),因为数组也是一个对象。

通过展开语法复制新的数组示例

setUsers( [

       ...users, // 新数组包含原数组的所有元素

        { id: 99, name: ‘麻五’} // 并在末尾添加了一个新的元素

 ]);

可以配合展开语法修改数组的方法

  • concat
  • [...arr]
  • filter
  • map
  • slice

以上方法均不改变原数组,返回一个新数组,可以配合展开语法来实现state数组类型的值修改

7 Immer更新数组

与对象一样,如果数组内部嵌套了较深层次的对象,更改起来也比较麻烦,通常有两种方式:

(1)调整数据结构,尽量做到扁平,避免嵌套太深

(2)如果涉及业务层面不能修改数据结构,就使用Immer库来修改

Immer库修改示例

updateUsers(draft => {
  const targetUser = draft.find(a => a.id === '123');
  targetUser.name = '麻五';
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妍思码匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值