React hooks 共享 state

2,256 阅读1分钟

useContext 需要注入基础信息与插入组件。

同层 state 共享又不在父组件通过 props 同步。遂尝试 hooks 同步方式。

大致思路:

  1. 使用闭包缓存 store 信息
  2. 单纯调用 useStatesetState 方法触发组件更新

配置基础功能

const useBase = (store, actions = []) => {
  const [, newChangeState] = useState();

  useEffect(() => {
    store.stateList.push(newChangeState);

    return () => {
      return (store.stateList = store.stateList.filter(
        self => self !== newChangeState
      ));
    };
  }, [store]);

  return [
    store.state,
    (() => {
      const selfActions = {};

      Object.keys(actions).forEach(funName => {
        if (typeof actions[funName] === 'function') {
          selfActions[funName] = actions[funName].bind(null, store);
        }
      });

      return selfActions;
    })(),
  ];
};

const useDefModule = (initState, actions) => {
  const store = { state: initState, stateList: [] };

  store.setState = newState => {
    store.state = { ...store.state, ...newState };
    store.stateList.forEach(fn => fn(store.state));
  };

  return useBase.bind(null, store, actions);
};

调用使用方式

const useModule = useDefModule.call(null, initState, {
  changeState: ({ setState }) => {
    setState({ value: Date.now() });
  },
});


const Item1 = () => {
  const [{ value }, { changeState }] = useModule();

  return (
    <div onClick={() => changeState({ value: Date.now() })}>123 {value}</div>
  );
};

const Item2 = () => {
  const [{ value }, { changeState }] = useModule();

  useEffect(() => {
    const id = setInterval(() => {
      changeState({ value: Date.now() });
    }, 1000);

    return () => clearInterval(id);
  }, [changeState]);

  return (
    <div onClick={() => changeState({ value: Date.now() })}>456 {value}</div>
  );
};

export default () => {
  const [show, changeShow] = useState(true);

  return (
    <>
      <Item1 />
      <button onClick={() => changeShow(!show)}>delete</button>
      {show && <Item2 />}
    </>
  );
};

使用 bindcall 纯粹为了屏蔽

ESLint: React Hook "useDefModule" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function.(react-hooks/rules-of-hooks)

参考链接 使用React Hooks进行状态管理 - 无Redux和Context API