阅读 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 模式的库
相关推荐
hiahiahia12317 分钟前
实现完整 Tool Dispatcher
开发语言·前端
IT_陈寒35 分钟前
Java线程池这破玩意,差点让我周末加班排查到凌晨
前端·人工智能·后端
Mr_Mao1 小时前
告别选型困难!集 VueUse、ahooks、Mantine 于一身:286 个 Hook 的 ReaUse 来了
前端·javascript·react.js
智鸟科技GemeOpen开发者智能设备1 小时前
智能插座二次开发如何接入Home Assistant,从零开始完整工程实现(Python+React)
开发语言·python·物联网·react.js·智能家居
泡海椒2 小时前
趋势分析报表:jquick-pdf折线图PDF生成实战
java·大数据·运维·服务器·前端·pdf
默_笙2 小时前
🚙 一条腿走路会摔:ES 关键词检索、混合召回与 ReRank 裁判
前端·javascript
YIAN2 小时前
从跨域代理到 WebSocket:梳理前端实时通信的底层逻辑与完整实践
前端·websocket
一曲终散2 小时前
创建 SVG 图标预览页面:从零实现到解决 CORS 问题
前端
静默回滚3 小时前
iPhone照片电脑上打不开:HEIC解码从原理到WASM
前端
dsyyyyy11013 小时前
Vue 3 Watch 监视完全指南
前端·javascript·vue.js