Is getState replaced by an enhancer not used within actions in redux?

61 Views Asked by At

I'm replacing getState with an enhancer as follows:

interface ArtificialStateEnhancerProps {
  getArtificialStateGetter: StateGetterFn;
}

export const getArtificialStateEnhancer = ({
  getArtificialStateGetter
}: ArtificialStateEnhancerProps) => {
  return (createStore: typeof createStoreOriginal) => {
    return (rootReducer, preloadedState, enhancers) => {
      const store = createStore(rootReducer, preloadedState, enhancers);

      const { getState } = store;

      if (getArtificialStateGetter) {
        return { ...store, getState: getArtificialStateGetter(getState) };
      }
      return { ...store };
    };
  };
};

When using store.getState() somewhere in my code it works an my custom getStage method is used. However within an Action or Sage (using select()) the original, native getState from redux is used.

Example action:

export function myAction(
  slug: string
): ReduxAction<any> {
  return async (
    dispatch: Dispatch,
    getState: () => any // Here getState is used but the native version of redux
  ): Promise<any> => {
    const state = getState();

    const foo = ...do something with `state`
  };
}

Is this intended behavior?

1

There are 1 best solutions below

5
markerikson On

It most likely depends on the ordering of where the middleware enhancer is added vs your custom enhancer.

If the middleware enhancer is added after the custom enhancer, then it is dealing with the base-level store methods. Each enhancer kind of "stacks" on top of each other.

My guess is that you've got something like:

compose(myCustomEnhancer, applyMiddleware(saga))

meaning that the middleware enhancer is after the custom one.

You'd need to flip those if that's the case.

(As a side question: could you give more details as to why you're writing a custom enhancer? It's a valid technique, but very rarely used, and it's even more rare that you would ever need or want to override getState.)

Also, note that we generally recommend against using sagas in almost all use cases, and especially if you're looking at using sagas for basic data fetching. Today, Redux Toolkit's "RTK Query" data fetching and caching API does a vastly better job of handling data fetching for you, and the RTK "listener" middleware handles the same reactive logic use case as sagas but with a simpler API, smaller bundle size, and better TS support.

See my talk The Evolution of Redux Async Logic for comparisons and explanations of why we recommend against sagas.