阅读 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 模式的库
相关推荐
伍哥的传说1 小时前
鸿蒙系统(HarmonyOS)应用开发之手势锁屏密码锁(PatternLock)
前端·华为·前端框架·harmonyos·鸿蒙
yugi9878381 小时前
前端跨域问题解决Access to XMLHttpRequest at xxx from has been blocked by CORS policy
前端
浪裡遊2 小时前
Sass详解:功能特性、常用方法与最佳实践
开发语言·前端·javascript·css·vue.js·rust·sass
旧曲重听12 小时前
最快实现的前端灰度方案
前端·程序人生·状态模式
默默coding的程序猿3 小时前
3.前端和后端参数不一致,后端接不到数据的解决方案
java·前端·spring·ssm·springboot·idea·springcloud
夏梦春蝉3 小时前
ES6从入门到精通:常用知识点
前端·javascript·es6
马特说3 小时前
React金融数据分析应用性能优化实战:借助AI辅助解决18万数据量栈溢出Bug
react.js·金融·数据分析
归于尽3 小时前
useEffect玩转React Hooks生命周期
前端·react.js
G等你下课3 小时前
React useEffect 详解与运用
前端·react.js
我想说一句3 小时前
当饼干遇上代码:一场HTTP与Cookie的奇幻漂流 🍪🌊
前端·javascript