From 001a1979372dbd9cf431805f439a179eb05e20be Mon Sep 17 00:00:00 2001 From: gupta Date: Wed, 31 Jul 2019 15:40:02 +0530 Subject: [PATCH 1/2] Fixed combineReducers changeDetection logic(#3488) --- src/combineReducers.js | 2 ++ test/combineReducers.spec.js | 51 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/combineReducers.js b/src/combineReducers.js index 05c9d56513..bdbcfb2291 100644 --- a/src/combineReducers.js +++ b/src/combineReducers.js @@ -173,6 +173,8 @@ export default function combineReducers(reducers) { nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } + hasChanged = + hasChanged || finalReducerKeys.length !== Object.keys(state).length return hasChanged ? nextState : state } } diff --git a/test/combineReducers.spec.js b/test/combineReducers.spec.js index 321010a598..f00aff9976 100644 --- a/test/combineReducers.spec.js +++ b/test/combineReducers.spec.js @@ -281,5 +281,56 @@ describe('Utils', () => { spy.mockClear() console.error = preSpy }) + + describe('With Replace Reducers', function() { + const foo = (state = {}) => state + const bar = (state = {}) => state + const ACTION = { type: 'ACTION' } + + it('should return an updated state when additional reducers are passed to combineReducers', function() { + const originalCompositeReducer = combineReducers({ foo }) + const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ foo, bar })) + store.dispatch(ACTION) + const nextState = store.getState() + expect(nextState).not.toBe(initialState) + }) + + it('should return an updated state when reducers passed to combineReducers are changed', function() { + const baz = (state = {}) => state + + const originalCompositeReducer = combineReducers({ foo, bar }) + const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ baz, bar })) + store.dispatch(ACTION) + const nextState = store.getState() + expect(nextState).not.toBe(initialState) + }) + + it('should return the same state when reducers passed to combineReducers not changed', function() { + const originalCompositeReducer = combineReducers({ foo, bar }) + const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ foo, bar })) + store.dispatch(ACTION) + const nextState = store.getState() + expect(nextState).toBe(initialState) + }) + + it('should return an updated state when one of more reducers passed to the combineReducers are removed', function() { + const originalCompositeReducer = combineReducers({ foo, bar }) + const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ bar })) + const nextState = store.getState() + expect(nextState).not.toBe(initialState) + }) + }) }) }) From 2c24ecce9ce818b9fc9c404059d0f277a650cd95 Mon Sep 17 00:00:00 2001 From: Tim Dorr Date: Mon, 12 Aug 2019 11:28:09 -0400 Subject: [PATCH 2/2] Cleaning up these and some other tests while I'm here --- test/combineReducers.spec.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/combineReducers.spec.js b/test/combineReducers.spec.js index f00aff9976..e0e69aa110 100644 --- a/test/combineReducers.spec.js +++ b/test/combineReducers.spec.js @@ -192,6 +192,7 @@ describe('Utils', () => { expect(spy.mock.calls[0][0]).toMatch( /Store does not have a valid reducer/ ) + spy.mockClear() console.error = preSpy }) @@ -265,13 +266,16 @@ describe('Utils', () => { const bar = (state = { bar: 2 }) => state expect(spy.mock.calls.length).toBe(0) + const reducer = combineReducers({ foo, bar }) const state = { foo: 1, bar: 2, qux: 3 } + reducer(state, {}) reducer(state, {}) reducer(state, {}) reducer(state, {}) expect(spy.mock.calls.length).toBe(1) + reducer({ ...state, baz: 5 }, {}) reducer({ ...state, baz: 5 }, {}) reducer({ ...state, baz: 5 }, {}) @@ -290,10 +294,14 @@ describe('Utils', () => { it('should return an updated state when additional reducers are passed to combineReducers', function() { const originalCompositeReducer = combineReducers({ foo }) const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ foo, bar })) store.dispatch(ACTION) + const nextState = store.getState() expect(nextState).not.toBe(initialState) }) @@ -303,10 +311,14 @@ describe('Utils', () => { const originalCompositeReducer = combineReducers({ foo, bar }) const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ baz, bar })) store.dispatch(ACTION) + const nextState = store.getState() expect(nextState).not.toBe(initialState) }) @@ -314,10 +326,14 @@ describe('Utils', () => { it('should return the same state when reducers passed to combineReducers not changed', function() { const originalCompositeReducer = combineReducers({ foo, bar }) const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ foo, bar })) store.dispatch(ACTION) + const nextState = store.getState() expect(nextState).toBe(initialState) }) @@ -325,9 +341,13 @@ describe('Utils', () => { it('should return an updated state when one of more reducers passed to the combineReducers are removed', function() { const originalCompositeReducer = combineReducers({ foo, bar }) const store = createStore(originalCompositeReducer) + store.dispatch(ACTION) + const initialState = store.getState() + store.replaceReducer(combineReducers({ bar })) + const nextState = store.getState() expect(nextState).not.toBe(initialState) })