Matt
Matt

Reputation: 8982

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

I tried simple react,redux,ajax working example and followed Reddit API tutorial, but I cannot create store and get error:

Uncaught Error: Expected the reducer to be a function.

index.jsx

...

import { createStore, applyMiddleware } from 'redux'
var thunkMiddleware = require('redux-thunk');
var createLogger = require('redux-logger');
var rootReducer = require('./reducers.js');

        const loggerMiddleware = createLogger();

        function configureStore(initialState) {
            return createStore(
                rootReducer,
                initialState,
                applyMiddleware(
                    thunkMiddleware,
                    loggerMiddleware
                )
            )
        }

        const store = configureStore();

...

rootReducer.js

import { combineReducers } from 'redux';

function products(state = {
    isFetching: false,
    didInvalidate: false,
    items: []
}, action) {
    switch (action.type) {
        case 'REQUEST_PRODUCTS':
            return Object.assign({}, state, {
                isFetching: true,
                didInvalidate: false
            })
        case 'RECEIVE_PRODUCTS':
            return Object.assign({}, state, {
                isFetching: false,
                didInvalidate: false,
                items: action.posts,
                lastUpdated: action.receivedAt
            })
        default:
            return state
    }
}

function specialPosts(state = { }, action) {
    switch (action.type) {
        case RECEIVE_SPECPOSTS:
        case REQUEST_SPECPOSTS:
            return Object.assign({}, state, {
                req: true
            })
        default:
            return state
    }
}

const rootReducer = combineReducers({
    products,
    specialPosts
});

export default rootReducer;

enter image description here

Type of rootReducer is object, but why? Should I change createStore function to rootReducer.default?

return createStore(
    rootReducer.default,
    initialState,
    applyMiddleware(
        thunkMiddleware,
        loggerMiddleware
     )
)

package.json

"redux-logger": "^2.6.1",
"react-redux": "^4.4.1",
"react-redux-provide": "^5.2.3",
"redux": "^3.3.1",
"redux-thunk": "^2.0.1",

Upvotes: 28

Views: 67963

Answers (8)

Lawrence E Bosumbe
Lawrence E Bosumbe

Reputation: 592

When you see this error: Uncaught Error: Expected the reducer to be a function, you must make sure that in src/index.js file, the second argument of the createStore() method must be a function.

This is wrong: const store = createStore(rootReducer, applyMiddleware)

This is ok: const store = createStore(rootReducer, applyMiddleware())

For new updated please use configureStore instead:

This is ok: const store = configureStore(rootReducer, applyMiddleware())

Upvotes: 0

Shahmir
Shahmir

Reputation: 91

i have faced the same problem and it is solved by

const redux = require('redux');
const store = redux.createStore(reducer);

and my reducer is

const reducer = (state = initailState, action)=>{
    if(action.type === 'BUY_CAKE'){

        return {...state, numOfCake : state.numOfCake + 1}
    }
    if(action.type === BUY_ICECREAM){

        return {...state, numOfIceCream : state.numOfIceCream + 1}
    }
}

Upvotes: 0

andras
andras

Reputation: 3655

When you see the error:

Uncaught Error: Expected the reducer to be a function

It does not necessarily mean that the reducer is not a function. If you experience this error, you should try creating the store with just the reducer. So like this:

createStore(reducer)

Which might be working.

In my case, the second parameter was wrong, because I didn't call compose and applyMiddleware in the correct order. So this is a correct setup that seems to have worked in my case:


export const createDebugStore = () => {
    const options: EnhancerOptions = {}
    const composeFunc = (typeof window !== 'undefined' && composeWithDevTools(options)) || compose;
    const enhancer = composeFunc(applyMiddleware());

    return createStore((state: any) => state || {}, enhancer);
}

Upvotes: 1

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20168

When you create store first argument must be function that means reduce(()=>[]) parameter

Error:

import {createStore,applyMiddleware} from 'redux';


export default function configureStore(initialState) {
  return createStore(
    [],
    {},
    applyMiddleware()
  );
}

Solution:

import {createStore,applyMiddleware} from 'redux';


export default function configureStore(initialState) {
  return createStore(
    ()=>[],
    {},
    applyMiddleware()
  );
}

Upvotes: 6

Matthis Kohli
Matthis Kohli

Reputation: 1993

I use VS Code Insiders and sometimes changes are not saved correctly. So if you followed all of the above and the error is still there go to each file and press STRG+S. It solved the issue for me.

Upvotes: 0

user8202629
user8202629

Reputation:

rootReducer

/* index.js */

import AppReducer from './reducers';
// import {AppReducer} from './reducers';
// bugs : must be a root reducer, can not be use as a module









/* reducers.js */ 

// initial state
const initialState = {
    angular: 0,
    react: 0,
    vuejs: 0
};


// reducers update state 
const AppReducers = (state = initialState, action) => {
    switch (action.type) {
        case 'VOTE_ANGULAR':
            console.log("Vote Angular!");
            return (
                Object.assign(
                    {}, 
                    state, 
                    {
                        angular: state.angular + 1
                    }
                )
            );
        case 'VOTE_REACT':
            console.log("Vote React!");
            return (
                Object.assign(
                    {}, 
                    state, 
                    {
                        react: state.react + 1
                    }
                )
            );
        case 'VOTE_VUEJS':
            console.log("Vote Vue.jsc!");
            return (
                Object.assign(
                    {}, 
                    state, 
                    {
                        vuejs: state.vuejs + 1
                    }
                )
            );
        default:
            return state;
    }
};

export {AppReducers};
export default AppReducers;

Upvotes: 0

Mike Lambert
Mike Lambert

Reputation: 1986

The problem was due to rootReducer being imported by "require" (ES5):

var rootReducer = require('./reducers.js');

If you import it via the ES6 method, it will correctly save the rootReducer.js' default automatically into rootReducer as you expected:

import rootReducer from './reducers';

I see you are mixing ES5 (require) and ES6 (import) in that file...I was mixing in my project as well, which is why I ran into this problem. More information can be found here: https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0#.2x2p2dx3m

Upvotes: 9

Tom
Tom

Reputation: 8180

const rootReducer = combineReducers({
    products,
    specialPosts
});

const store = createStore( rootReducer, applyMiddleware( thunkMiddleware ));

The initial state is then created automatically from the initial states returned by the individual reducer functions. These individual states can be accessed as state.products and state.specialPosts

Upvotes: 17

Related Questions