Skip to content

MinJieLiu/immot

Repository files navigation

immot

NPM version Build status Test coverage Downloads Minified size Gzip size

在不改变原始数据的情况下,创建新的拷贝。

安装

pnpm i immot

或者

yarn add immot

介绍

不可变数据 是函数式编程中极其重要的一个基本概念。Reactstate 设计为只读,即 不可变数据,只能通过 setState 修改。此模块可以完美配合 React,以简化 setState 操作不可变数据的繁琐步骤。

React 中,你不能这样做:

state.a.b.c = 1;
// or...
state.c.d.f.push(2);

通常,你会这样做:

const nextState = {
  ...state,
  a: {
    ...state.a,
    b: {
      ...state.a.b,
      c: 1,
    },
  },
};

现在有了 immot,让操作深层数据变得简单:

const nextState = $setIn(state, ['a', 'b', 'c'], 1);

nextState === state;
// false

注意 immot 不是深拷贝,深拷贝操作极其昂贵,无法适用于日常开发。immot 只会创建改变的数据,会引用原对象中未改变的部分。

immot 的 API 灵感来自于 immutable-js,但 immutable-js 有独立的结构模型,复杂度高。immot 的设计理念是要求简单、易用,不需要过多的心智负担。因此在设计之初就亲和原生的 JSON 结构,只提供辅助函数,大小 < 1KB,就做到像 immutable-js 一样的效果。

immot 做到了 typescript 类型安全。$updateIn$setIn$mergeIn 中的 keyPath 路径支持类型自动提示(目前只支持小于 7 层结构)。

code.gif

使用

import * as immot from 'immot';

或者只导入其中某个函数

import { $updateIn } from 'immot';

immot 所有函数操作都会返回一个新的对象。

$set

用于设置 对象/数组/Map 中的属性值。keyPath 为字符串。

const result = immot.$set(demo, 'a', 1);

$setIn

用于设置 对象/数组/Map 中的属性值。它可以为深层对象做操作,keyPath 为路径数组

const result = immot.$setIn(demo, ['a', 'b', 1, 'c'], 'good');

$merge

用于合并 对象/数组 中的属性列表。

const result = immot.$merge(demo, { tom: 1, jack: 2 });

const result1 = immot.$merge(demo1, [5, 6]);

$mergeIn

用于合并 对象/数组 中的属性列表。它可以为深层对象做操作,keyPath 为路径数组

const result = immot.$mergeIn(demo, ['a', 1, 'b'], { tom: 1, jack: 2 });

$update

通过回调函数设置 对象/数组/Map 中的属性值。keyPath 为字符串。

const result = immot.$update(demo, 'money', (prev) => prev + 1);

$updateIn

通过回调函数设置 对象/数组/Map 中的属性值。它可以为深层对象做操作,keyPath 为路径数组

const result = immot.$updateIn(demo, ['todoList', 0, 'complete'], (complete) => !complete);

$delete

用于删除 对象/数组/Map 中的可选属性值,keyPath 为字符串或者数组

const result = immot.$delete(demo, 'a1');
const result1 = immot.$delete(demo, ['a1', 'a2']);

$push

类似 Array.prototype.push,但返回新数组

const result = immot.$push(demo, 4);

$pop

类似 Array.prototype.pop,但返回新数组

const result = immot.$pop(demo);

$shift

类似 Array.prototype.shift,但返回新数组

const result = immot.$shift(demo);

$unshift

类似 Array.prototype.unshift,但返回新数组

const result = immot.$unshift(demo, 4);

$splice

类似 Array.prototype.splice,但返回新数组

const result = immot.$splice(demo, 1, 0, 'test');

性能测试

/bench 目录中有性能测试对比的样例,可以 clone 本项目测试

cd bench
pnpm i
node index.mjs

注意:

  1. 数值为每秒操作数量,越高越好
  2. 样例中 immer 关闭了自动冻结对象的特性,否则结果会更差。
  3. 数组性能测试图中隐藏了 immutableJS 数据,用空间换取时间的方式导致数值太高,影响对比。

在 Node v14.17.0 的测试结果:

常规数据和深层数据 Performance

50000 长度的数组 Performance1