baronnoraz
baronnoraz

Reputation: 568

React + Redux-router = Uncaught Error: Expected the reducer to be a function

My code is working fine, but I have an annoying problem whenever I make a coding mistake and get a runtime error. For instance, in one of my JSX pages I did Date() instead of new Date() and instead of reporting the actual error, I got...

Uncaught Error: Expected the reducer to be a function.

Any error I make almost always shows up as this. It's being reported from createStore.js, which is in my configureStore.jsx code below.

Is there a way that I can get better error reporting that helps me identify the real problem? Any help or ideas are greatly appreciated!!!

Here's my setup for reference....

main.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ReduxRouter } from 'redux-router';
import configureStore from './store/configureStore'
import routes from './routes';

const rootEl = document.getElementById('app-container');

const store = configureStore();

ReactDOM.render(
    <div>
        <Provider store={store}>
            <ReduxRouter routes={routes} />
        </Provider>
    </div>
    , rootEl
);

configureStore.jsx

import { createHashHistory } from 'history';
import { applyMiddleware, createStore, compose } from 'redux';
import { reduxReactRouter } from 'redux-router';

import thunk from 'redux-thunk';
import promiseMiddleware from 'redux-promise-middleware';

import rootReducer from '../reducers/rootReducer';
import routes from '../routes';

export default function configureStore(initialState = {}) {

    const history = createHashHistory();

    const middlewares = [
        thunk,
        promiseMiddleware({
            promiseTypeSuffixes: ['PENDING','SUCCESS','ERROR']
        })
    ];

    const toolChain = [
        applyMiddleware(...middlewares),
        reduxReactRouter({
            routes,
            history
        })
    ];

    const store = compose(...toolChain)(createStore)(rootReducer, initialState);

    if (module.hot) {
        module.hot.accept('../reducers', () => {
            const nextRootReducer = require('../reducers/rootReducer');
            store.replaceReducer(nextRootReducer);
        });
    }
    return store;
}

rootReducer.jsx

import { combineReducers } from 'redux';
import { routerStateReducer } from 'redux-router';
import siteReducer from './siteReducer';

const rootReducer = combineReducers({
    router: routerStateReducer,
    sites: siteReducer
});
export default rootReducer;

siteReducer.jsx

import {GET_SITES} from '../actions/siteActions';

const defaultState = {
    isPending: null,
    isSuccess: null,
    isError: null,
    error: null,
    data: null
};

export default function siteReducer(state = defaultState, action) {

    switch (action.type) {
        case `${GET_SITES}_PENDING`:
            return {
                ...defaultState,
                isPending: true
            };
        case `${GET_SITES}_SUCCESS`:
            return {
                ...defaultState,
                isSuccess: true,
                error: false,
                data: action.payload
            };
        case `${GET_SITES}_ERROR`:
            return {
                ...defaultState,
                isError: true,
                error: action.payload
            };
        default:
            return state;
    }
}

Upvotes: 19

Views: 15261

Answers (3)

sledgeweight
sledgeweight

Reputation: 8115

My issue was importing Store from the root reducer path rather than the actual bundled store root (with devtools on the window and root reducer, middleware being composed, etc).

import Store from '../../../src/state/Store/reducer';

changed to

import Store from '../../../src/state/Store';

Upvotes: 0

danludwig
danludwig

Reputation: 47350

Change the following line:

const nextRootReducer = require('../reducers/rootReducer');

To:

const nextRootReducer = require('../reducers/rootReducer').default;

Upvotes: 11

Umang Gupta
Umang Gupta

Reputation: 16510

Use export const variable_name instead of const variable_name whenever you want to export that variable.

For ex: rootReducer.jsx should be re-written as

import { combineReducers } from 'redux';
import { routerStateReducer } from 'redux-router';
import siteReducer from './siteReducer';

export const rootReducer = combineReducers({
router: routerStateReducer,
sites: siteReducer
});
export default rootReducer;

Note the extra export specifier with const rootReducer

Upvotes: 4

Related Questions