Skip to content

Commit c2bf13c

Browse files
committed
move combine reducers sanity check
1 parent 4071451 commit c2bf13c

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

src/utils/combineReducers.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ function verifyStateShape(inputState, outputState, action) {
7272

7373
export default function combineReducers(reducers) {
7474
var finalReducers = pick(reducers, (val) => typeof val === 'function');
75+
var sanityError;
7576

7677
Object.keys(finalReducers).forEach(key => {
7778
var reducer = finalReducers[key];
78-
if (typeof reducer(undefined, { type: ActionTypes.INIT }) === 'undefined') {
79-
throw new Error(
79+
if (!sanityError && typeof reducer(undefined, { type: ActionTypes.INIT }) === 'undefined') {
80+
sanityError = new Error(
8081
`Reducer "${key}" returned undefined during initialization. ` +
8182
`If the state passed to the reducer is undefined, you must ` +
8283
`explicitly return the initial state. The initial state may ` +
@@ -85,8 +86,8 @@ export default function combineReducers(reducers) {
8586
}
8687

8788
var type = Math.random().toString(36).substring(7).split('').join('.');
88-
if (typeof reducer(undefined, { type }) === 'undefined') {
89-
throw new Error(
89+
if (!sanityError && typeof reducer(undefined, { type }) === 'undefined') {
90+
sanityError = new Error(
9091
`Reducer "${key}" returned undefined when probed with a random type. ` +
9192
`Don't try to handle ${ActionTypes.INIT} or other actions in "redux/*" ` +
9293
`namespace. They are considered private. Instead, you must return the ` +
@@ -100,6 +101,9 @@ export default function combineReducers(reducers) {
100101
var defaultState = mapValues(finalReducers, () => undefined);
101102

102103
return function combination(state = defaultState, action) {
104+
if (sanityError) {
105+
throw sanityError;
106+
}
103107
var finalState = mapValues(finalReducers, (reducer, key) => {
104108
var newState = reducer(state[key], action);
105109
if (typeof newState === 'undefined') {

test/utils/combineReducers.spec.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ describe('Utils', () => {
6666
);
6767
});
6868

69-
it('should throw an error if a reducer returns undefined initializing', () => {
70-
expect(() => combineReducers({
69+
it('should throw an error on first call if a reducer returns undefined initializing', () => {
70+
const reducer = combineReducers({
7171
counter(state, action) {
7272
switch (action.type) {
7373
case 'increment':
@@ -78,7 +78,8 @@ describe('Utils', () => {
7878
return state;
7979
}
8080
}
81-
})).toThrow(
81+
});
82+
expect(() => reducer({})).toThrow(
8283
/"counter".*initialization/
8384
);
8485
});
@@ -100,8 +101,8 @@ describe('Utils', () => {
100101
expect(reducer({counter: 0}, { type: increment }).counter).toEqual(1);
101102
});
102103

103-
it('should throw an error if a reducer attempts to handle a private action', () => {
104-
expect(() => combineReducers({
104+
it('should throw an error on first call if a reducer attempts to handle a private action', () => {
105+
const reducer = combineReducers({
105106
counter(state, action) {
106107
switch (action.type) {
107108
case 'increment':
@@ -115,7 +116,8 @@ describe('Utils', () => {
115116
return undefined;
116117
}
117118
}
118-
})).toThrow(
119+
});
120+
expect(() => reducer()).toThrow(
119121
/"counter".*private/
120122
);
121123
});

0 commit comments

Comments
 (0)