美文网首页
【Immer】---Immer基本使用

【Immer】---Immer基本使用

作者: DY_alley | 来源:发表于2020-05-28 21:26 被阅读0次

一、前言

Immer 是 mobx 的作者写的一个 immutable 库,核心实现是利用 ES6 的 proxy,几乎以最小的成本实现了 js 的不可变数据结构,简单易用、体量小巧、设计巧妙,满足了我们对JS不可变数据结构的需求。

二、Immutable的缺陷问题

  • 需要使用者学习它的数据结构操作方式,没有 Immer 提供的使用原生对象的操作方式简单、易用;
  • 它的操作结果需要通过toJS方法才能得到原生对象,这使得在操作一个对象的时候,时刻要注意操作的是原生对象还是 ImmutableJS 的返回结果,稍不注意,就会产生意想不到的 bug。

三、immer基本使用

语法:produce(currentState, recipe: (draftState) => void | draftState, ?PatchListener): nextState

  • defaultState:

    ​ 被操作对象的最初状态

  • draftState:

    根据 defaultState 生成的草稿状态,它是defaultState的代理,对draftState 所做的任何修改都将被记录并用于生成 nextState。在此过程中,defaultState 将不受影响

  • nextState:

    根据draftState 生成的最终状态

  • produce:

    用来生成 nextStateproducer 的函数

  • producer 生产者
    通过 produce 生成,用来生产nextState ,每次执行相同的操作

  • recipe 生产机器
    用来操作draftState 的函数

const { produce } = require('immer');

let defaultState = {
    num: 10,
    str: 'alley',
    arr: [10,20,30,40],
    obj: {
        nickname:'alley-巷子',
        age:20
    }
}

let data = produce(defaultState, drafy => {
    drafy.num = 100;
})

console.log(data === defaultState ) // false;

3-1、原理

const { produce } = require('immer');

    let defaultState = {
        num: 10,
        str: 'alley',
        arr: [10,20,30,40],
        obj: {
            nickname:'alley-巷子',
            age:20
        }
    }
    
    let nextState = produce(defaultState, draftState => {
        draftState.arr.push(100);
    })

    console.log(nextState === defaultState ) // false;
    console.log(nextState.arr === defaultState.arr ) // false;
    console.log(nextState.num === defaultState.num ) // true; 
    console.log(nextState,defaultState)

由此可见,对 draftState 的修改都会反应到nextState 上,而 Immer 使用的结构是共享的,nextState 在结构上又与 currentState 共享未修改的部分,共享效果如图(借用的一篇Immutable文章中的动图,侵删):

Immer 还在内部做了一件很巧妙的事情,那就是通过 produce 生成的 nextState 是被冻结(freeze)的,(Immer 内部使用``Object.freeze方法,只冻结 nextState currentState相比修改的部分),这样,当直接修改nextState时,将会报错。 这使得nextState `成为了真正的不可变数据

4039331718-56cc22613b287_articlex.gif

3-2、高阶函数用法

语法:produce(recipe: (draftState) => void | draftState, ?PatchListener)(currentState): nextState

recipe 是否有返回值,nextState 的生成过程是不同的:

  • recipe 没有返回值时:nextState是根据recipe 函数内的 draftState生成的;
  • recipe有返回值时:nextState是根据 recipe 函数的返回值生成的;
let producer = produce((draft) => {
      draft.x = 2
    });
    let nextState = producer(currentState);




    /* 没有返回值  */
    let producer = produce((draft) => {
        draft.num = 100;
    });

    let nextState = producer(defaultState);

    console.log(nextState);
    /*
        {
            num: 100,
            str: 'alley',
            arr: [ 10, 20, 30, 40 ],
            obj: { nickname: 'alley-巷子', age: 20 }
        }
    */



    /* 有返回值 */
    let producer = produce((draft) => {
        return {
            num:11
        }
    });
    
    let nextState = producer(defaultState);

    console.log(nextState);
    /*
        {
            num: 11
        }
    */

3-3、recipe中的this

ecipe 函数内部的this指向 draftState ,也就是修改this与修改 recipe 的参数 draftState ,效果是一样的。
注意:此处的 recipe 函数不能是箭头函数,如果是箭头函数,this就无法指向 draftState 了

produce(currentState, function(draft){
  // 此处,this 指向 draftState
  draft === this; // true
})

本文章参考:https://segmentfault.com/a/1190000017270785

相关文章

网友评论

      本文标题:【Immer】---Immer基本使用

      本文链接:https://www.haomeiwen.com/subject/qfezahtx.html