阅读 zustand.js

前言

最近在看一些状态管理的库,zustand 目前是社区比较流行的选择,所以先阅读下它的源码,来理解它是如何解决前端状态管理的问题的。

  • 最先应该是问题
  1. 为什么它性能会好一些?
  2. 为什么它的侵入性比较低?
  3. 它的生态怎么样?是否有商用的案例?
  • 为了解决这些问题,它设计了哪些 API,主要会产生什么能力

根据问题来依次解决

1. 为什么它性能会好一些?

首先它能够基于 Selector 进行精准更新,所以相对 Context-Provider 之类的管理模式,避免了 Context 范围内的大量更新,以及 Context 订阅失效的一些问题,性能自然会好一些。但是 mobx 等依然也能精准更新,那么它的优势是什么呢?

看完源码后其实它享受了 React 的福利,那就是 useSyncExternalStore 接入三方 Store 绑定 Fiber State 的能力,这样让 zustand 的结构相当简单,库也很好,没有 mobx 那么多依赖复杂。zustand 更像是一个更好的 Redux 模型升级。

2. 为什么它的侵入性比较低?

概要结构

因为它的实现其实很简单,我们先来看下它的源码 src 目录和 API 设计自然就了解。其中 vanilla.ts 是核心的功能实现,src/react.ts 是连接 react 能力的核心实现。

bash 复制代码
├── context.ts
├── index.ts
├── middleware
│   ├── combine.ts
│   ├── devtools.ts
│   ├── immer.ts
│   ├── persist.ts
│   ├── redux.ts
│   └── subscribeWithSelector.ts
├── middleware.ts
├── react
│   └── shallow.ts
├── react.ts
├── shallow.ts
├── traditional.ts
├── types.d.ts
├── vanilla
│   └── shallow.ts
└── vanilla.ts

整体 zustand 的 API 包含以下内容,除去扩展能力,核心能力比较少。

源码设计

源码部分,基本就是一个 Redux 基础模型的实现,主要有这么几个:以下是伪代码

javascript 复制代码
// 1. setState 的时候,批量支持订阅的监听器
setState() {
    if (Object.is(nextState, state)) return;
    
    // 存下 prev
    const prevState = state;
    
    // 开始产生新 state
    state = replace ? nextState : assign({}, state, nextState);
    
    // 执行监听器
    each(listeners, (listener) => listener(state, prevState))
}

// 2. getState 就是简单获取
getState() {
    return state;
}

// 3. getInitialState 拥有动态的能力
getInitialState -> state -> createState(setState, getState, api);

// 4. subscribe 就是一个监听数组操作
subscribe(listener) {
    listeners.add(listener);
    
    return () => listeners.delete(listener);
}

实现这个之后,zustand 基本能力的组合就到了 react.ts,核心就是使用 React.useSyncExternalStoreWithSelector,所以这里就能看出为什么侵入性是很弱的,自身 core 部分的实现就是纯 JS 能力。

javascript 复制代码
// 核心就这么一句
const slice = useSyncExternalStoreWithSelector(
  api.subscribe,
  api.getState,
  api.getServerState || api.getInitialState,
  selector,
  equalityFn,
)

那么,其实这里有个疑问,为什么这就生效了呢?这里和 Zustand 就没有太大关系了,这里解释一下 React 这里核心的实现,其实很好理解,React 拥有 Fiber 更新的能力,我们只需要在 Fiber Change 过程,添加一个 subscribe 的回调给到三方就可以实现能力。

javascript 复制代码
// React 中的核心连接实现
// packages/react-reconciler/src/ReactFiberHooks.js
function subscribeToStore<T>(
  fiber: Fiber,
  inst: StoreInstance<T>,
  subscribe: (() => void) => () => void,
): any {
  const handleStoreChange = () => {
    // The store changed. Check if the snapshot changed since the last time we
    // read from the store.
    if (checkIfSnapshotChanged(inst)) {
      // Force a re-render.
      forceStoreRerender(fiber);
    }
  };
  // Subscribe to the store and return a clean-up function.
  
  // 重点就是这里了~其实在内部是放了 forceStoreRerender 的回调
  return subscribe(handleStoreChange);
}

有深入兴趣的同学可以再研究了,其实从理解 Zustand 基本就是这些内容,毕竟我们不需要帮 React CV 一个 useSyncExternalStore。这里还有个可以研究的点就是 withSelector,可以看下基础的实现,是基于 memo state 的模式。

最后总结:zustand + React 是基于 useSyncExternalStore 能力实现的 Redux 😄

它的生态怎么样?是否有商用的案例?

  • 整体趋势
    • 可以看出基本已经是前三的位置,并且有上涨趋势,就像自己理解的,他可能是继承 Redux 模式的库
相关推荐
apcipot_rain3 小时前
【应用密码学】实验五 公钥密码2——ECC
前端·数据库·python
ShallowLin3 小时前
vue3学习——组合式 API:生命周期钩子
前端·javascript·vue.js
Nejosi_念旧3 小时前
Vue API 、element-plus自动导入插件
前端·javascript·vue.js
互联网搬砖老肖3 小时前
Web 架构之攻击应急方案
前端·架构
pixle04 小时前
Vue3 Echarts 3D饼图(3D环形图)实现讲解附带源码
前端·3d·echarts
麻芝汤圆4 小时前
MapReduce 入门实战:WordCount 程序
大数据·前端·javascript·ajax·spark·mapreduce
juruiyuan1116 小时前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭6 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
LuckyLay8 小时前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf8 小时前
典籍知识问答重新生成和消息修改Bug修改
前端·bug