Search code examples
javascriptreduxredux-devtoolsredux-toolkitredux-devtools-extension

Can't add tracing functionality in Redux with Next.js


I'd like to add the tracing functionality to my dev tools in Redux:

However I when doing this:

export default () => {
  let store;
  const isClient = typeof window !== 'undefined';
  if (isClient) {
    const { persistReducer } = require('redux-persist');
    const storage = require('redux-persist/lib/storage').default;
    const persistConfig = {
      key: 'root',
      storage,
      stateReconciler: autoMergeLevel2,

      whitelist: ['users', 'ui'] // place to select which state you want to persist
    };

   ******composeEnhancers******

    var composeEnhancers =
      typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
        ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
            // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
          })
        : compose;

    composeEnhancers = composeWithDevTools({
      actionCreators,
      trace: true,
      traceLimit: 25
    });

    store = createStore(
      persistReducer(persistConfig, rootReducer),
      composeEnhancers(
        applyMiddleware(thunkMiddleware, createLogger({ collapsed: false }))
      )
    );

  ******composeEnhancers******

    store.__PERSISTOR = persistStore(store);
  } else {
    store = createStore(
      rootReducer,
      composeEnhancers(
        applyMiddleware(thunkMiddleware, createLogger({ collapsed: false }))
      )
    );
  }
  return store;
};

I get the following error...

Unhandled Runtime Error
TypeError: composeEnhancers is not a function

Call Stack
module.exports../store/index.js.__webpack_exports__.default
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/.next/server/static/development/pages/_app.js (499:84)
createStore
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (95:20)
initStore
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (98:20)
Object.<anonymous>
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (137:33)
step
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (56:23)
Object.next
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (37:53)
<unknown>
file:///Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/next-redux-wrapper/lib/index.js (31:71)
new Promise
<anonymous>

Thanks in advance!

UPDATE

Followed a thread from redux-toolkit and I think I am halfway there, but now I am getting the following which seems odd considering my setup:

Error: "reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers

This is my updated store:

import { combineReducers } from 'redux';
import { configureStore } from '@reduxjs/toolkit';
import { createLogger } from 'redux-logger';

/* imported reducers */
import ui from './reducers/ui/index';
import users from './reducers/users/index';

import thunkMiddleware from 'redux-thunk';
import { persistStore } from 'redux-persist';

import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
import { persistReducer } from 'redux-persist';

var reducers = combineReducers({
  users: users,
  ui: ui
});

export default () => {
  let store;
  const isClient = typeof window !== 'undefined';
  if (isClient) {
    var storage = require('redux-persist/lib/storage').default;
    var persistConfig = {
      key: 'root',
      storage,
      stateReconciler: autoMergeLevel2,

      whitelist: ['users', 'ui'] // place to select which state you want to persist
    };

    var persistedReducer = persistReducer(persistConfig, reducers);

    store = configureStore({
      reducer: persistedReducer,
      middleware: [thunkMiddleware, createLogger()]
    });
    store.__PERSISTOR = persistStore(store);
  } else {
    store = configureStore({
      reducer: persistedReducer,
      middleware: [thunkMiddleware, createLogger()]
    });
  }
  return store;

Solution

  • I'd specifically recommend switching to using the configureStore API from our official Redux Toolkit package. It already has this option turned on by default, and it will handle setting up the rest of your store with good defaults as well.

    update

    That error sounds like you're not actually passing a reducer field to configureStore.

    Per your updated code, I'm pretty sure this else block is wrong:

        store = configureStore({
          reducer: persistedReducer,
          middleware: [thunkMiddleware, createLogger()]
        });
    

    Based on your logic, persistedReducer only exists in the if block, so it's undefined in the else block.

    Also, your use of the middleware arg is currently leaving out all the automatic use of dev check middleware.

    I'd suggest rewriting this as:

    export default () => {
      let rootReducer;
      const isClient = typeof window !== 'undefined';
      if (isClient) {
        // redux-persist setup logic here
        rootReducer = persistReducer(persistConfig, reducers);
      } else {
        rootReducer = reducers;
      }
    
      const store = configureStore({
        reducer: rootReducer,
         middleware: [...getDefaultMiddleware(), createLogger()]
      })
    
      return store
    }