Получить текущее состояние из useReducer вне компонента React - PullRequest
1 голос
/ 22 апреля 2019

Я использую хук useReducer с Context для создания хранилища состояний Redux, поддерживающего промежуточное ПО.

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

Учитывая, что промежуточное ПО thunk будет действовать наасинхронные действия, в идеале мы могли бы пропустить функцию для извлечения текущего состояния при необходимости - getState - вместо того, чтобы принудительно использовать состояние в том виде, в каком оно существовало на момент применения промежуточного программного обеспечения, что может быть устаревшим.

Обычно я передаю что-то вроде этого:

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

Но если я передаю это промежуточному программному обеспечению для вызова, я получаю ошибку, указывающую, что я могу вызывать только перехватчики из функций React .

Я что-то неправильно понимаю?Не правильно ли я заворачиваю голову вокруг крючков?

ОБНОВЛЕНИЕ: добавление запрашиваемой 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;
};
...