手写zustand

206 阅读1分钟

Zustand 状态库汇总已经介绍了zustand相关所有知识点,包括它的使用还有原理,今天重点直接实现一个迷你的zustand。

基础使用如下:

import { create } from 'zustand';

const useStore = create((set, get) => ({
  a: '',
  b: 0,
  updateA: (value) => set(() => ({ a: value })),
  updateB: (value) => set(() => ({ b: value })),
  getA: () => get().a,
  getB: () => get().b,
}));

export default function App() {
  const {
    a,
    b,
    updateA,
    updateB,
    getA,
    getB } = useStore();

  return (
    <div style={{ margin: '100px' }}>
      <input
        onChange={(e) => updateA(e.currentTarget.value)}
        value={a}
      />
      <p>hello, {a}</p>
      <p>a 的值, {getA()}</p>
      <button onClick={() => { updateB(b + 1); }}>点我</button>
      <div>{b}</div>
      <p>b 的值, {getB()}</p>
    </div>
  );
}

测试如下:

image.png

我们先创造一个create的函数:

import { useState, useEffect } from 'react';

const createStore = (createState) => {
  let state;
  const listeners = new Set();

  const setState = (partial, replace) => {
    const nextState = typeof partial === 'function' ? partial(state) : partial;

    if (!Object.is(nextState, state)) {
      const previousState = state;

      if (!replace) {
        state = (typeof nextState !== 'object' || nextState === null)
          ? nextState
          : Object.assign({}, state, nextState);
      } else {
        state = nextState;
      }
      listeners.forEach((listener) => listener(state, previousState));
    }
  };

  const getState = () => state;

  const subscribe = (listener) => {
    listeners.add(listener);
    return () => listeners.delete(listener);
  };

  const destroy = () => {
    listeners.clear();
  };

  const api = { setState, getState, subscribe, destroy };

  state = createState(setState, getState, api);

  return api;
};


//轻质更新
function useStore(api) {
  const [, forceRender] = useState(0);
  useEffect(() => {
    api.subscribe((state, prevState) => {
      forceRender(Math.random());
    });
  }, []);

  return api.getState();
}

export const create = (createState) => {
  const api = createStore(createState);
  const useBoundStore = () => useStore(api);
  Object.assign(useBoundStore, api);

  return useBoundStore;
};

其实就是一个订阅模式,然后在useEffect里面每次都给useState设置随机数,要他强制刷新,就好了!现在一个简单的zustand就好了。

测试成功:

image.png

接下来就是扩展的事情了,希望你们自行扩展!