redux-actions: handleActions returning defaultState even when state passed is not undefined

import { handleActions } from 'redux-actions';

const getInitialState = () => {
    return ['red'];
};

const reducer = handleActions({
    test: (state, action) => {
        return action.payload.a ? undefined : ['yellow'];
    },
    test2: (state) => {
        return ['1'];
    }
}, getInitialState());

const reducer2 = handleActions({
    test: (state, action) => {
        return action.payload.a ? undefined : ['yellow'];
    }
}, getInitialState());

console.log(reducer(['green'], {
    type: 'test',
    payload: {
        a: 1
    }
}));
// ['red']

console.log(reducer2(['green'], {
    type: 'test',
    payload: {
        a: 1
    }
}));
// undefined

The first console statement returns the defaultState which is ['red'] whereas the second console statement returns undefined even though they both respond to the same action and have same action handling logic. Can someone tell me why is this happening?

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Comments: 22 (11 by maintainers)

Most upvoted comments

The issue is not with this library, it’s actually because of reduce-reducers which is being used by handleActions. reduce-reducers reduces multiple reducers into one reducer by the following code

export default function reduceReducers(...reducers) {
  return (previous, current) =>
    reducers.reduce(
      (p, r) => r(p, current),
      previous
    );
}

So the reason why test case A fails is because since the first reducer inside handleActions returns undefined, the second reducer will get undefined as the initial state and will return the default state. But if we push the test reducer to the end inside handleActions, then it will receive the actual state and will return undefined. So the following test case will pass.

it('A', () => {
        const reducer = handleActions({
            test2: (state) => {
                return ['1'];
            },

            // add this at the end
            test: (state, action) => {
                return action.payload.a ? undefined : ['yellow'];
            }
        }, defaultState);

        expect(reducer(['green'], { type: 'test', payload: { a: 1 } })).to.deep.equal(undefined);
    });

So I don’t think there is anything to fix here since reducers should not be returning undefined in the first place, but it’ll be good if an error is thrown when a reducer returns undefined so that the user knows there is a problem, otherwise the reducer might return incorrect state which might lead to unexpected results in the application