我想再来谈谈Immer —— 用法篇

起因
 
之前已经写过一篇关于Immer的介绍,这次还想再详细谈谈Immer ,主要的原因有以下两点
 
Web业务越来越复杂,原来React工程里推荐的范式化的数据结果不适合于像低代码平台这类复杂业务了,并且同时也想维持状态是不可变的特点
 
Immer本身也得到了广泛关注和认可,在Redux最新推荐的Redux Toolkit 中就集成了Immer
 
Immer的单词来自于德语里的“永远”,它工作原理如同下图所示
 
Immer并不会对原有的状态数据进行直接更改,这样就保持了不可变性,但是在使用语法上却是直接赋值,注意如图所示,直接赋值的对象并不是原有的状态数据,而是另一个Draft对象。
 
说一下我心中的Immer的定位,Immer跟Vue、Redux 、React 、Mobx这些库里的状态管理机制相比,我觉得它处在一个半自动挡的位置,Vue 和Mobx处在自动挡的位置,也就是说状态改变后它们会去自动触发DOM更新等副作用,而React、Redux处在手动挡的地位,甚至于状态数据的变化,也不能直接修改,经常看到的是做浅拷贝,以下例子摘自Immer官网
 
 const nextState = baseState.slice() // 浅拷贝
 
 nextState[1] = {
 
     // 替换元素
 
     …nextState[1], // 浅拷贝位置1的元素
 
     done: true // 修改
 
 }
 
 ​
 
 nextState.push({title: “Tweet about it”})
 
假如数据结构层次很深,同时又不想做范式化,因为一些业务场景范式化后的数据在使用时也还是要整合起来,不如直接使用树状数据来的方便,此时修改数据简直就是噩梦,所以Immer针对的就是这种情况,它仅仅是处理了复杂数据的更新,并不涉及到副作用,以下例子摘自Immer官网
 
 import produce from “immer”
 
 ​
 
 const nextState = produce(baseState, draft => {
 
     draft[1].done = true
 
     draft.push({title: “Tweet about it”})
 
 })
 
可以看到,现在要得到更新后的状态非常方便了,但如同刚才所说的一样,Immer也仅仅只是半自动化,不涉及副作用,所以一般最后我们还是要调用setState 或者其他的操作来完成最终的业务目的。
 
安装
 
 npm install immer
 
要注意的是如果想要得到额外的支持,还需要调用一些引入API,同时打包结果也会变大
 
支持
调用
 
支持ES5
enableES5()
 
支持Map和Set数据结构
enableMapSet()
 
支持JSON Patch
enablePatches()
 
以上所有都想支持
enableAllPlugins()
 
用法
 
 // 在应用的入口处
 
 import {enableMapSet} from “immer”
 
 ​
 
 enableMapSet()
 
 ​
 
 // …稍后
 
 import produce from “immer”
 
 ​
 
 const usersById_v1 = new Map([
 
     [“michel”, {name: “Michel Weststrate”, country: “NL”}]
 
 ])
 
 ​
 
 const usersById_v2 = produce(usersById_v1, draft => {
 
     draft.get(”michel”)。country = “UK”
 
 })
 
 ​
 
 const usersById_v3 = produce(usersById_v1, draft => {
 
     draft.set(”michel”, {name: “Michel Weststrate”, country: “NL”})
 
 })
 
 ​
 
 ​
 
使用produce
 
Immer的要点就在于produce的使用,它的签名如下
 
 produce(currentState, recipe: (draftState) => void): nextState
 
注意这些名称
 
produce
 
recipe
 
draftState / draft
 
producer
 
 
这些名称没法硬翻,或者翻译后失去味道,只能靠揣摩和感悟
 
一个produce的HW代码如下
 
 import produce from “immer”
 
 ​
 
 const baseState = [
 
     {
 
         title: “Learn TypeScript”,
 
         done: true
 
     },
 
     {
 
         title: “Try Immer”,
 
         done: false
 
     }
 
 ]
 
 ​
 
 const nextState = produce(baseState, draftState => {
 
     draftState.push({title: “Tweet about it”})
 
     draftState[1].done = true
 
 })
 
对了,HW不是华为,是Hello World
 
除了刚才的用法,produce函数还有一种柯里化方式的调用,在后面的源码篇中也会看到原理

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h64069.shtml

张贴在3