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 };