Search code examples
typescriptnext.jsreduxredux-toolkitredux-devtools

Next JS Redux Devtools extension not working


I am trying to setup Redux-Devtools extension for this simple NextJS app with Redux, but the configuration is not working. I am having issue in enhancer and have no clue how to resolve this issue.

I read through the Redux documentation but unable to find the right information thats needed to get it to work. Any guidance to this will be of great help.

VS code Error I am receiving is:

Type '((...args: any[]) => unknown)[]' is not assignable to type '(getDefaultEnhancers: GetDefaultEnhancers<Tuple<[ThunkMiddleware<CombinedState<{ cards: CardState; }>, UnknownAction>]>>) => Tuple<...>'.

The expected type comes from property 'enhancers' which is declared here on type 'ConfigureStoreOptions<CombinedState<{ cards: CardState; }>, UnknownAction, Tuple<[ThunkMiddleware<CombinedState<{ cards: CardState; }>, UnknownAction>]>, Tuple<...>, CombinedState<...>>'

Store.ts

import { configureStore } from "@reduxjs/toolkit";
import { composeWithDevTools } from "@redux-devtools/extension";
import {
  TypedUseSelectorHook,
  useDispatch as useAppDispatch,
  useSelector as useAppSelector,
} from "react-redux";
import { applyMiddleware, compose } from "redux";
 
import rootReducer from "./rootReducer";
// And use redux-batched-subscribe as an example of adding enhancers
// ----------------------------------------------------------------------

// Define the root state type using the ReturnType utility of TypeScript
export type RootState = ReturnType<typeof rootReducer>;

// Define the type for dispatching actions from the store
export type AppDispatch = typeof store.dispatch;


const composeEnhancers = compose(
  applyMiddleware,
  composeWithDevTools()
);

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
      immutableCheck: false,
    }),
  devTools: process.env.NODE_ENV !== 'production',
  enhancers: [composeEnhancers],
});

// Extract the dispatch function from the store for convenience
const { dispatch } = store;

const useSelector: TypedUseSelectorHook<RootState> = useAppSelector;

// Create a custom useDispatch hook with typed dispatch
const useDispatch = () => useAppDispatch<AppDispatch>();

// Export the Redux store, dispatch, useSelector, 
// and useDispatch for use in components
export { store, dispatch, useSelector, useDispatch };

Solution

  • Adding store enhancers works similarly to the middleware, you can provide an array of enhancers (Typescript users must use a Tuple) or use the getDefaultEnhancers function to append them.

    import {
      configureStore,
      applyMiddleware ,
      Tuple
    } from '@reduxjs/toolkit';
    
    const store = configureStore({
      reducer: rootReducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          serializableCheck: false,
          immutableCheck: false,
        }),
      devTools: process.env.NODE_ENV !== 'production',
      enhancers: (getDefaultEnhancers) =>
        getDefaultEnhancers()
          .concat(/* ...other enhancers */),
    });
    

    or

    const store = configureStore({
      reducer: rootReducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          serializableCheck: false,
          immutableCheck: false,
        }),
      devTools: process.env.NODE_ENV !== 'production',
      enhancers: () => new Tuple(applyMiddleware, /* ...other enhancers */),
    });
    

    The default enhancers always already includes the applyMiddleware enhancer based on the middleware property, and includes the autoBatchEnhancer.

    The devTools are handled separately so there's no need to do anything for it in the enhancers property. devTools is either a boolean value or an object, and defaults to true.

    The following setup will disable the default serializability and immutability checks, and enable the devtools with default settings in non-production builds.

    const store = configureStore({
      reducer: rootReducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          serializableCheck: false,
          immutableCheck: false,
        }),
      devTools: process.env.NODE_ENV !== 'production',
    });
    

    You can pass an object for devTools if you would like to customize its settings.

    const store = configureStore({
      reducer: rootReducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          serializableCheck: false,
          immutableCheck: false,
        }),
      devTools: process.env.NODE_ENV !== 'production' && {
        maxAge: 100, // default 50
        trace: true, // default false
        ...etc
      },
    });