Skip to content

Commit

Permalink
REPLACE action for replaceReducers (#2673)
Browse files Browse the repository at this point in the history
* Add an explicit private action type for replacing reducers

* Make this a const while we're at it...

* Triple equals for lint

* Add a random string to the "private" actions.
  • Loading branch information
timdorr committed Nov 16, 2017
1 parent 0b6d794 commit e6f6c7d
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/combineReducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, une
unexpectedKeyCache[key] = true
})

if (action && action.type === ActionTypes.REPLACE) return

if (unexpectedKeys.length > 0) {
return (
`Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` +
Expand Down
2 changes: 1 addition & 1 deletion src/createStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export default function createStore(reducer, preloadedState, enhancer) {
}

currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
dispatch({ type: ActionTypes.REPLACE })
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/utils/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
var ActionTypes = {
INIT: '@@redux/INIT'
const ActionTypes = {
INIT: '@@redux/INIT' + Math.random().toString(36).substring(7).split('').join('.'),

This comment has been minimized.

Copy link
@cyberhck

cyberhck Apr 16, 2018

Just curious, why is this actually necessary? Normally we'd just say to user this is private action, and not to use them, which is mentioned so in the comment. This feels more like restriction, rather than suggestion. I do have a case where I'd actually want to capture this in my saga and also dispatch my separate "INIT"

This comment has been minimized.

Copy link
@cyberhck

cyberhck Apr 20, 2018

Never mind, I understood the intent for this, for someone wondering, it's for internal purpose and shouldn't be handled, if you try to handle it, it'll break hot reloading, (you don't want that)

REPLACE: '@@redux/REPLACE' + Math.random().toString(36).substring(7).split('').join('.')
}

export default ActionTypes
26 changes: 26 additions & 0 deletions test/createStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -767,4 +767,30 @@ describe('createStore', () => {
expect(results).toEqual([ { foo: 0, bar: 0, fromRx: true }, { foo: 1, bar: 0, fromRx: true } ])
})
})

it('does not log an error if parts of the current state will be ignored by a nextReducer using combineReducers', () => {
const originalConsoleError = console.error
console.error = jest.fn()

const store = createStore(
combineReducers({
x: (s=0, a) => s,
y: combineReducers({
z: (s=0, a) => s,
w: (s=0, a) => s,
}),
})
)

store.replaceReducer(
combineReducers({
y: combineReducers({
z: (s=0, a) => s,
}),
})
)

expect(console.error.mock.calls.length).toBe(0)
console.error = originalConsoleError
})
})

0 comments on commit e6f6c7d

Please sign in to comment.