react useReactStore.js

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import _get from 'lodash.get';
import _set from 'lodash.set';

export const KEY_SAVED_TICK_COUNT = 'KEY_SAVED_TICK_COUNT';

export class GlobalStore {
  constructor(initialValues) {
    this.storeData = initialValues || {};
    this.watcherList = []; // {path, watcher, preValue}
    this.tickCount = 0;
  }

  getValue(path) {
    return _get(this.storeData, path);
  }

  setValue(path, value) {
    this.tickCount += 1;
    _set(this.storeData, path, value);
    _set(this.storeData, KEY_SAVED_TICK_COUNT, this.tickCount);
    this.notifyWatcher();
  }

  watch(path, watcher, from) {
    if (typeof watcher !== 'function') {
      throw 'watcher must function';
    }
    this.watcherList.push({ path, watcher, preValue: undefined });
    console.log('GlobalStore watch', from, this.watcherList.length);
  }

  unwatch(path, watcher, from) {
    this.watcherList = this.watcherList.filter((obj) => {
      return obj.path !== path || obj.watcher !== watcher;
    });

    console.log('GlobalStore unwatch', from, this.watcherList.length);
  }

  notifyWatcher() {
    const watcherList = this.watcherList || [];
    for (let i = 0; i < watcherList.length; i++) {
      const { path, watcher, preValue } = watcherList[i];
      const nextValue = this.getValue(path);
      if (preValue !== nextValue) {
        watcher(nextValue, preValue, this);
        watcherList[i].preValue = nextValue;
      }
    }
  }
}

/**
 * 创建一个GlobalStore
 * @param initialValues
 */
function useCreateGlobalStore(initialValues) {
  return useMemo(() => {
    return new GlobalStore(initialValues);
  }, []);
}

/**
 * 订阅并获取value的变化
 * @param store
 * @param path
 */
function useGlobalValue(store, path) {
  const valueRef = useRef();

  const [value, setValue] = useState(() => {
    const nowValue = store.getValue(path);
    valueRef.current = nowValue;
    return nowValue;
  });

  useEffect(() => {
    const init = () => {
      const nextValue = store.getValue(path);
      if (valueRef.current !== nextValue) {
        valueRef.current = nextValue;
        setValue(nextValue);
      }
    };

    init();

    const watcher = (nextValue) => {
      console.log('useGlobalValue nextValue', nextValue);
      if (valueRef.current !== nextValue) {
        valueRef.current = nextValue;
        setValue(nextValue);
      }
    };

    store.watch(path, watcher);

    return () => {
      store.unwatch(path, watcher);
    };
  }, [store, path]);

  /**
   * 更新值
   */
  const updateValue = useCallback(
    (nextValue) => {
      store.setValue(path, nextValue);
    },
    [store, path],
  );

  /**
   * 在Render之前获取最新值
   */
  const getCurrent = useCallback(() => {
    return valueRef.current;
  }, [[store, path]]);

  return [value, updateValue, getCurrent, store];
}

export { useCreateGlobalStore, useGlobalValue };

  

posted on 2023-05-12 13:03  袜子破了  阅读(29)  评论(0编辑  收藏  举报