第22节——Immutable Data 不可变数据

一、概念

Immutable 意为「不可变的」。在编程领域,Immutable Data 是指一种一旦创建就不能更改的数据结构。它的理念是:在赋值时,产生一个与原对象完全一样的新对象,指向不同的内存地址,互不影响

二、作用

1、避免副作用

当我们需要对一个对象进行修改时,直接在原对象上进行变更很方便,也很节省内存。但是在 js 中,对象都是引用类型,在按引用传递数据的场景中,会存在多个变量指向同一个内存地址的情况,这样会引发不可控的副作用

const a = { x: 1 };
const b = a;
b.x = 6;

a.x // 6

在一个复杂应用中,如果有多个代码块同时更改这个引用,就会产生竞态。你需要关心这个对象会在哪个地方被修改,你对它的修改会不会影响其他代码的运行。使用 Immutable Data 就不会产生这个问题——因为每当状态更新时,都会产生一个新的对象

let a = { x: 1, y: 2 }; // 初始状态

a = { ...a, x: 6 }; // 创建了一个新的对象,更新了 a

// do something

2、状态可追溯

由于每次修改都会创建一个新对象,且对象不变,那么变更的记录就能够被保存下来,应用的状态变得可控、可追溯。Redux Dev Tool 和 Git 这两个能够实现「时间旅行」的工具就是秉承了 Immutable 的哲学

三、为什么 React 需要 Immutable Data

简单来说为了让 React 精准地重渲染 UI。我们知道,在 React 中,UI 是 state 的投影,state 的变更会引发 UI 的重新渲染。React 使用 Virtual DOM 来解决 UI 更新的问题——它会将新旧两棵 Virtual DOM 树进行比较,如果两者存在差异,则它会将这些差异来更新在真实的 DOM 上。

调用setState时,React 会以 shallowMerge(浅层合并) 的方式将我们传入的对象与旧的 state 进行合并。shallowMerge 只会合并新旧 state 对象中第一层的内容,如果 state 中对象的引用未变,那么 React 认为这个对象前后没有发生变化。所以如果我们以 mutable 的方式更改了 state 中的某个对象, React 会认为该对象并没有更新,那么相对应的 UI 就不会被重渲染。而以 Immutable 的方式更新 state 就不会出现这个问题

import React, { useState } from "react";


export default function App() {
  const [list, setList] = useState([1, 2, 3]);

  const addMutable = () => {
    list.push("新数据");
    setList(list);
  };

  const addImmutable = () => {
    setList([...list, "新数据"]);
  };

  return (
    <div className="App">
      <button onClick={addMutable}>已可变的方式添加</button>
      <button onClick={addImmutable}>已不可变的方式添加</button>
      {list.map((item, index) => (<li key={index}>{item}</li>))}
    </div>
  );
}

四、优秀的开源库

redux / flux 要求采用返回新对象的形式,来触发数据更新、re-render,一般推荐的做法就是采用对象解构的方式。如果 state 对象巨大(注意:对象巨大),在解构、拷贝 state 的过程中,耗时会较长。

return {
  ...state,
  settings: {
    ...state.settings,
    profile:{
      ...state.settings.profile,
      darkmode: true,
    }
  }
}

immutable-js、immer,我们着重了解一下immer

1、immer(获过奖的创新型玩法)

https://immerjs.github.io/immer/zh-CN/

**开源库实现思路:**原始对象先做了一层 Proxy 代理,得到 draftState 传递给 function。function(带副作用) 直接更改 draftState,最后 produce 返回新的对象

安装

npm install immer

使用

import React, { useState } from "react";
import produce from "immer";


export default function App() {
  const [list, setList] = useState([1, 2, 3]);

  const addMutable = () => {
    list.push("新数据");
    setList(list);
  };

  const addImmutable = () => {
    /**
     * 第一个参数是要代理的数据
     * 第二个参数是一个函数
     */
    const newVal = produce(list, draft => {
      /**
       * draft 相当于 list
       * 在这个方法里面,可以直接修改draft,注意draft也只能在这个方法里面修改
       * 不需要返回值,immer内部已经帮我处理好了
       */
      draft.push('新数据')
    })
    console.log(newVal)
    setList(newVal);
  };

  return (
    <div className="App">
      <button onClick={addMutable}>已可变的方式添加</button>
      <button onClick={addImmutable}>已不可变的方式添加</button>
      {list.map((item, index) => (<li key={index}>{item}</li>))}
    </div>
  );
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值