Skip to content

Redux.replaceReducer throw warning "Unexpected key found" #1636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andreechristian opened this issue Apr 19, 2016 · 15 comments
Closed

Redux.replaceReducer throw warning "Unexpected key found" #1636

andreechristian opened this issue Apr 19, 2016 · 15 comments

Comments

@andreechristian
Copy link

andreechristian commented Apr 19, 2016

This issue was moved from reduxjs/react-redux#360

Hello,
I tried to do a code splitting on route change.

When the route changes to '/register', i dynamically add "registration" as one of the root state using replaceReducer and it work just fine.
Once the registration completed i want to remove the reducer using replaceReducer again, but instead it return the following warning :

Unexpected key "registration" found in initialState argument passed to createStore. Expected to find one of the known reducer keys instead: ... Unexpected keys will be ignored.

Thanks in advance

@andreechristian
Copy link
Author

Basically, i cannot remove a 'sub state' once it is added to the store :(

@gaearon
Copy link
Contributor

gaearon commented Apr 19, 2016

Technically this is a warning rather than an error so you can. But it is annoying. I think we should fix this.

@cpeddecord
Copy link

I'm running into this warning after adding serialized state from a server handoff whilst routing into a route with a dynamically added reducer. Only happens on initial load as my routes initialize on the client after the store. Wondering if there's a good workaround here...

@andreechristian
Copy link
Author

andreechristian commented Apr 20, 2016

I think after changing current reducer into next reducer, we should trim unnecessary state from current state based on next reducer keys. Or if the store doesn't have multiple reducers, do something like recreating store state based on next reducers default action => and then assign current state data that matches next state data. And only after that we should dispatch the INIT.

@andreechristian
Copy link
Author

andreechristian commented Apr 20, 2016

Also @gaearon, although this is a warning, it seemed to me that the state doesn't necessarily changed. I still got 'registration' as one of my root state. Or is it expected? But if it is expected, then my 'registration' state will gonna be a dead meat right there, right? The reducer's gone but the state remains.

@gaearon
Copy link
Contributor

gaearon commented Apr 20, 2016

I would suggest removing that warning in the source and checking which tests fail. They likely show reasonable ideas or why this warning was added. Then we can consider how to make it works well for all use cases.

@flucivja
Copy link

flucivja commented Jun 2, 2016

Hi,

I came across same issue when I am trying to build modular application. The basic idea is that once module is loaded it will inject its own reducers and once module is unloaded it should remove its own reducers.
I've accomplished it with usage with react-router and using onEnter and onLeave hooks. Basically onEnter hook inject module's reducers with replaceReducer and dispatch actions 'a1', 'a2', 'a3' on the injected reducers. Then once user navigates outside of the module, module`s reducers are removed in onLeave hook also with usage of replaceReducer.
The issue is that and I got above warning too but the bigger issue is that also all 'a1', 'a2', 'a3' actions are dispatched again and I am not sure why because I don't dispatch these actions in onLeave hook. Do you have some idea why this happens?

@edit
strikeout issue which was my bad :)

Thanks.

@BryceHayden
Copy link

BryceHayden commented Jun 9, 2016

I've been messing around with updating, and in some cases replacing the reducers based on dynamic routes. I posted a comment in response to @gaearon answer on stack overflow. I followed his answer for getting the reducers injected into the store, but I ran into a problem when I wanted to inject more reducers dealing with the same branch on the state tree on a different route. I couldn't figure out a way to combine the reducers that were already present and the new reducers. I don't want to combine these sooner as it allows me to code split the reducers down to what each page actually needs.

@gaearon
Copy link
Contributor

gaearon commented Jun 9, 2016

@QuietOmen Please post your question on SO, doesn’t look like this thread would be very helpful 😉

@BryceHayden
Copy link

Thanks, I posted it here in case anyone stumbles upon this thread and becomes curious.

@objectivePinta
Copy link

Ran in this issue, when writing a test for the store

@SijieCai
Copy link

SijieCai commented Mar 31, 2017

CombineReducer only show this warning on non-production environment, so a workaround could be:

  // on route leaving
  if (process.env.NODE_ENV === 'production') {
     // remove reducer here
  }

@timdorr
Copy link
Member

timdorr commented Oct 22, 2017

I would suggest removing that warning in the source and checking which tests fail. They likely show reasonable ideas or why this warning was added. Then we can consider how to make it works well for all use cases.

These two tests fail. Specifically, lines 237 and 285.

The 2nd test is just checking that the warning only fires once. But the 1st test is the interesting one: It's ensuring the provided initial state matches the state the current reducer provides. This makes sense for SSR; you want to make sure you're using the same reducer(s) for generating the page on the server as are running in the client.

It would seem we need to handle the special case of replacing a reducer separately from a initial store creation. So, I'd like to propose that the action dispatched after replaceReducers is a new type called "REPLACE" that is also special like INIT. Just some quick fiddling around proves this still passes all tests. Since it's a breaking behavior (even though it should be private...), I'll put it on the next branch for 4.0 stuff.

@acidicX
Copy link

acidicX commented Nov 3, 2017

I can confirm that if this warning appears, it seems to break clientside tree rehydration when using SSR:

React attempted to reuse markup in a container but the checksum was invalid.

@timdorr timdorr closed this as completed Nov 3, 2017
@budarin
Copy link

budarin commented Nov 9, 2017

@gaearon
What should I do in case of a page has been rendered on server synchronously (while on client it is loading lazily with dynamically injecting reducers) ?

So full state came to client and when store is created in the first time - store looses piece of state of the current page - because it's not loaded yet.
When page has been lazily loaded and has injected its reducers - state is 'clean' from data for the page - so component should do the logic it has done on server again

Is there a way to restore state with injecting reducers?
it would be logical to transfer the initial state together with new reducers, otherwise we should long way to recover that state which has come from server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants