I'm trying to set up my test environment that includes React Testing Library, Redux Toolkit, RTK Query and TypeScript but I've run into a problem I can't resolve.
The main issue I can't figure out is how to generate the AppDispatch type as explained in the documentation here when supplying a preloadedState.
Going by the RTK docs and using configureStore() directly is no problem, as the store is being created inside the module:
const store = configureStore({
reducer: {
home: homeReducer,
[homeApi.reducerPath]: homeApi.reducer,
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(
homeApi.middleware,
),
});
export type RootState = ReturnType<typeof store.reducer>;
export type AppDispatch = typeof store.dispatch; // not a problem as store exists here
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export default store;
However, doing it this way makes it difficult to pass a preloadedState value to configureStore() and keep the generated types. If I extract the reducer and use combineReducers() I can generate RootState from there, but I still can't figure out how to export AppDispatch as store.dispatch doesn't exist until the store is created, and in order to pass preloadedState I need to delay the creation of the store.
export const rootInitialState: Pick<RootState, 'home'> = {
home: homeInitialState,
};
const reducer = combineReducers({
home: homeReducer,
[homeApi.reducerPath]: homeApi.reducer,
});
export type RootState = ReturnType<typeof reducer>;
// this is the problem as store is created externally to this module,
// so how can I extract this type now?
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export const createStore = (preloadedState: Partial<RootState>) => configureStore({
reducer,
preloadedState,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(
homeApi.middleware,
),
});
Can this actually be done? At this point I'm totally stumped so if anyone can either offer a solution or put me out of my misery, I'd be hugely appreciative either way.