从React组件外部的useReducer检索当前状态

时间:2019-04-22 19:58:14

标签: reactjs redux react-hooks

我正在利用带有上下文的useReducer钩子来创建支持中间件的Redux-ish状态存储。

const Provider = (props: any) => {
  const [state, dispatch] = React.useReducer(reducer, {
    title: 'Default title',
    count: 0,
  });

  const actionDispatcher = makeActionDispatcher(
    dispatch,
    applyMiddleware(state, thunkMiddleware, callApiMiddleware, logger),
  );

  return (
    <Context.Provider value={{ ...state, ...actionDispatcher }}>
      {props.children}
    </Context.Provider>
  );
};

请注意,我正在将state传递给applyMiddleware

const applyMiddleware = (state: {}, ...middlewares: Function[]) =>
  function dispatcher(dispatch: Function) {
    const middlewareAPI = {
      state,
      dispatch: (...args) => dispatch(...args),
    };
    const chain = middlewares.map((middleware) => {
      return middleware(middlewareAPI);
    });
    return compose(...chain)(dispatch);
  };

这可行,但是最终我希望能够使用异步动作,因此理想情况下,我会使用类似redux-thunk的东西:

function thunkMiddleware(store: Store) {
  return (next: Function) => (action: any) => {
    typeof action === 'function' ? action(next, store.getState) : next(action);
  };
}

鉴于笨拙的中间件将对异步操作起作用,理想情况下,我们可以传递一个函数以在需要时检索当前状态-getState-而不是被迫使用中间件时存在的状态已应用,可能已过时。

通常我会把这样的东西传下来:

const getState = () => React.useReducer(reducer, {
    title: 'Default title',
    count: 0,
  })[0];

但是如果我将其传递给要调用的中间件,则会收到一条错误消息,指示可以only call hooks from React functions

我在设计错误的东西吗?我不是把头缠在钩子上吗?

更新:添加请求的makeActionDispatcher实现

export const makeActionDispatcher = (
  dispatch: React.Dispatch<any> | undefined,
  enhancer?: Function,
): ActionDispatcher => {
  const actionDispatcher: { [key: string]: (...args: any) => void } = {};

  Object.keys(actionCreators).forEach((key) => {
    const creator = actionCreators[key];
    actionDispatcher[key] = (...args: any) => {
      if (!dispatch) {
        throw new Error('ActionDispatcher has not been initialized!');
      }

      const action = creator(...args);

      if (enhancer) {
        const enhancedDispatch = enhancer(dispatch);
        enhancedDispatch(action);
      } else {
        dispatch(action);
      }
    };
  });

  return actionDispatcher as ActionDispatcher;
};

1 个答案:

答案 0 :(得分:1)

使用here中引入的useEnhancedReducer钩子。

然后您将得到类似的东西。

const [state, dispatch, getState] = useEnahancedReducer(reducer, initState)

由于dispatchgetState永远不会改变,因此您可以将其传递给某个挂钩,而无需将它们添加到依赖项列表中或将其存储在其他地方以从外部调用它们。

同一篇文章中还提供了useEnhancedReducer版本,该版本支持添加中间件。