本文主要对比不使用immer和使用immer的情况
注意:zustand中间件的immer是依赖immer库的,所以需要安装immer
npm i immer
一、使用immer
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
const useCountStore = create()(
immer((set) => ({
count: 0,
increment: (qty) =>
set((state) => {
state.count += qty
}),
decrement: (qty) =>
set((state) => {
state.count -= qty
}),
})),
)
function ZustandImmer() {
const { count, increment, decrement } = useCountStore()
console.log(count, 'count');
return (
<>
<h1>ZustandImmer</h1>
{count}
<br />
<button onClick={() => {increment(1)}}>+1</button>
<button onClick={() => {decrement(1)}}>-1</button>
</>
)
}
export default ZustandImmer
二、不使用immer
import { create } from 'zustand'
const useCountStore = create()(
(set) => ({
count: 0,
increment: (qty) =>
// 主要是这里不一样,因为这里set传进去的state是可变的,所以必须返回一个需要被改变的对象
set((state) => ({ count: state.count += qty })),
decrement: (qty) =>
set((state) => ({ count: state.count -= qty })),
}),
)
function ZustandWithoutImmer() {
const { count, increment, decrement } = useCountStore()
console.log(count, 'count');
return (
<>
<h1>ZustandImmer</h1>
{count}
<br />
<button onClick={() => {increment(1)}}>+1</button>
<button onClick={() => {decrement(1)}}>-1</button>
</>
)
}
export default ZustandWithoutImmer
优势
除了简化代码和避免错误外,使用immer中间件最主要的还是性能方面也做了优化
Immer 使用了一种称为结构共享的技术,可以有效地复用未修改的数据,从而减少内存使用和提高性能。
结构共享技术
结构共享是一种优化技术,主要用于不可变数据结构。当你创建一个新的数据结构作为旧数据结构的修改结果时,结构共享可以帮助你复用尽可能多的旧数据结构的部分,而不是完全复制整个数据结构。
例如,假设你有一个包含一百万个元素的数组,你想创建一个新的数组,它与旧数组完全相同,只是第一个元素不同。如果你完全复制整个数组,那么你需要创建一个新的一百万个元素的数组,这将消耗大量的内存和计算资源。但是,如果你使用结构共享,你只需要创建一个新的包含一个元素的数组,并将其与旧数组的剩余部分共享,这将大大减少内存和计算资源的消耗。
在 JavaScript 中,一些库(如 Immutable.js 和 Immer)使用了结构共享技术来优化不可变数据的处理。这使得你可以在不牺牲性能的情况下,享受不可变数据带来的好处,如简化的代码和更容易的状态管理。
小结
Zustand 的 immer 中间件允许你在更新状态时使用 Immer 库的不可变数据模式。这意味着你可以编写看起来像是直接修改状态的代码,但实际上你是在创建一个新的状态。
Immer 库的主要优点是它允许你以一种更直观和易于理解的方式来处理不可变数据。在 JavaScript 中,处理不可变数据通常需要使用诸如 Object.assign 或展开运算符(...)等操作,这些操作可能会使代码变得复杂和难以阅读。而使用 Immer,你可以编写看起来像是直接修改数据的代码,但实际上你是在创建一个新的、修改后的数据副本。
对于上面使用immer中间件的例子来说,increment和decrement传进去的state是一个不变值,可以理解为被freezed了,所以state直接被修改后,会对修改的节点进行创建并替换对应的节点上,所以不需要做赋值操作
而没有使用immer中间件的例子,是一个可变值,意味着,传入什么值就修改什么值