mutation概念与Immer库的使用

发布时间:2024年01月18日

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 = '麻五';
});
文章来源:https://blog.csdn.net/wjs0406/article/details/135666394
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。