50行实现zustand,一起探索原理和其设计模式。

58 阅读2分钟

可调试的demo案例具体实现

整个zustand的核心部分。

可以拆成两块实现:

  • 1、核心store对象 —— createStore(创造一个store实例)
  • 2、将store的变更同步给React,让他更新。 —— useStore(暴露出state快照)

如何链接 store 和 react呢?

react 提供了 useSyncExternalStore 这么一个Hook。 从英文上理解一下, “同步使用外部的store”

然后我们看一下官网(zh-hans.react.dev/reference/r…

参数:

  • 1、subscribe 函数应当订阅该 store 并返回一个取消订阅的函数。
  • 2、getSnapshot 函数应当从该 store 读取数据的快照。

我们能够从 subscribe 里拿到订阅者的信息,将它们都收集起来。而每次的store状态就由getSnapshot 传给react。 所以我们在createStore 提供两个方法 subscribegetStore ,订阅 和 拿到当前值。

import React from 'react'

/**
 * 整个zustand的核心部分。
 * 可以拆成两块实现:
 * 1、核心store对象 —— createStore(创造一个store实例)
 * 2、将store的变更同步给React,让他更新。 —— useStore(暴露出state快照)
 * 
 * 如何链接 store 和 react呢?
 *  react 提供了 useSyncExternalStore 这么一个Hook。
 *  从英文上理解一下, “同步使用外部的store”
 * 
 *  然后我们看一下官网(https://zh-hans.react.dev/reference/react/useSyncExternalStore)
 *  参数: 
 *  1、subscribe 函数应当订阅该 store 并返回一个取消订阅的函数。
 *  2、getSnapshot 函数应当从该 store 读取数据的快照。
 * 
 *  因此我们能够从 subscribe 里拿到订阅者的信息,将它们都收集起来。
 */

// 1、核心store对象
// 整个store作为一个观察者
const createStore = (createState) => {
  let state
  const listeners = new Set() // 订阅者

  // 仿照 setState 的执行实现
  const setState = (partial) => {
    console.log(state)
    const nextState = typeof partial === 'function' ? partial(state) : partial

    if(!Object.is(nextState, state)) {
      const preveState = state
      // 每次都产生一个新的对象,来保证快照不同。(核心因为react以Object.is方法来判断的)
      state = Object.assign({}, state, nextState)

      // 更新时,通知所有订阅者
      listeners.forEach(listener => listener(state, preveState))
    }
  }

  const getState = () => state

  const subscribe = (listener) => {
    listeners.add(listener)
    return () => {
      listeners.delete(listener)
    }
  }
  const getInitialState = () => initialState
    
  const api = { setState, getState, getInitialState, subscribe }
  const initialState = (state = createState(setState, getState, api))
  return api
}

// 2、 具体链接的实现
const useStore = (api, selector) => {
  const subscribe = api.subscribe
  if(!selector) selector = (state) => state
  const slice = React.useSyncExternalStore(subscribe, () => selector(api.getState()), () => selector(api.getState()))
  return slice
}
const createImpl = (createState) => {
  // 第一步
  const api = createStore(createState)
  // 第二步
  const useBoundary = (selector) => useStore(api, selector)
  return useBoundary
}

export const create = (createState) => typeof createState === 'function' ? createImpl(createState) : createImpl