-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
ReactReduxContext - infinite loop with react-hot-loader #1155
Comments
Yipes, long complicated comment. TBH, I just skimmed through this. I've never worked with SSR, so all that stuff is mostly over my head. Per your questions about the We've now got this behavior documented: Accessing the Store. |
Ok folks, I have very good news 👍 . I succeeded to make it work with react-hot-loader. First of all, we now know how to reproduce this issue. It appears when we use The simplest solution I came for is to simply use a The correct code looks like: import React, {Component} from "react";
import universal from "react-universal-component";
import { injectReducer } from "redux-reducers-injector";
import { ReactReduxContext } from "react-redux";
class Universal extends Component {
constructor(props) {
super(props);
this.firstRender = true;
}
render() {
const UniversalComponent = universal(import("./component"), {
loading: <span>loading</span>,
onLoad: (module, info, { reduxcontext }) => {
if (reduxcontext && reduxcontext.store) {
injectReducer("api", module.reducer, false, reduxcontext.store);
}
}
if (this.firstRender) {
this.firstRender = false;
return (<ReactReduxContext.Consumer>
{(reduxContext) => <UniversalComponent reduxcontext={reduxContext}/>}
</ReactReduxContext.Consumer>);
}
return <UniversalComponent/>;
});
export default Universal; Hope it will help others. Thank you, |
Hello there,
I'm creating this issue as a following of #1126
I've discovered a new issue regarding multiple concurrent calls on the server side, and its fix leads me to a new issue: an infinite loop when using hot reloading with react-hot-loader. I need your enlightenment.
I described more precisely the new issue here: faceyspacey/react-universal-component#172
First of all, we need to clearly identify what can possibly going wrong, we will separate the client side from the server side at the beginning to conjugate them at the ending.
First issue: @rgrove described it very well with
<Provider> misses state changes that occur between when its constructor runs and when it mounts
in #1126.We found a solution that is working great by using an HOC https://codesandbox.io/s/ryxk561qp4:
It works great on the client AND works great on the server.
But in a real application, you can have concurrent server calls. The best way to illustrate it is when using a service worker for caching routes.
Scenario with SSR + Service worker cache client:
server render app -> client loads app and takes priority -> service worker file is fetched and initialized -> routes to cache are fetched concurrently
Second issue: when injecting a reducer (dynamic loading) from a lazy loaded component, we need the
store
reference. In a single page app, thestore
is a singleton. On the server, with concurrent calls, thestore
is overrided. Which leads to errors when trying to render components that need injected reducer.Example: two concurrent calls -> server render app with a global store -> inject reducer in the global store -> global store is reinitialized from the second concurrent call -> render of the component fail.
Same issue as the first one.
For fixing this we need to inject the reducer in a context store. This way we secure one store by concurrent call for the rendering of our routes.
From [email protected], using
static contextTypes
for thestore
won't work. And so these lines will not pass the context store: https://github.com/faceyspacey/react-universal-component/blob/master/src/index.js#L110What I'm using for loading component lazily is
react-universal-component
: https://github.com/faceyspacey/react-universal-component.As you can see in the documentation, the
onLoad
method allow me to do things on the store like injecting reducers or dispatching actions:Now, the fourth parameter context gives
{store: undefined, report: undefined}
. Which does not allow us to use a context store and fixing our issue.So I thought about using the
ReactReduxContext
for passing it myself. In my opinion,react-universal-component
and other lazy loading libraries should not have to deal withredux
/react-redux
. The wayreact-universal-component
could work with the redux store before 6.0.0 was a convenient enhancement.You can read the issue on
react-universal-component
here: faceyspacey/react-universal-component#172Updating my codesandbox, I ran into some funny issues.
This one does not work: https://codesandbox.io/s/5mk3564w0k
This one works: https://codesandbox.io/s/vmwm085633
The modification is in the
route.js
file.I wrap my lazy loaded component in the
ReactReduxContext.Consumer
for getting the context store.Interestingly using the props
context
will not work, and using the propsreduxcontext
will.I wonder why, If you have any idea about that. I do not see why context should be a reserved name for a props.
By writing:
we fixed our issue! 🎉 it is working great on the server with concurrent calls and on the client.
Unfortunately there is a very uncomfortable side effect.
With this new code, adding the
ReactReduxContext.Consumer
for the lazy loading part; if we modify something in our component and we have hot reload activated withreact-hot-loader
, it leads to an infinite render loop.I'm really curious to understand what is going on.
Is this a bug with
react-hot-loader
or withreact-redux
? Having oneConsumer
, then a child with aProvider
and inside this child aConsumer
again, all from the same context leads to this behavior when hot reloading do things?As we cannot put
react-hot-loader
in a codesandbox sample, this issue is worth having its own project.I'll create it if anyone is interested for testing things.
Furthermore, I retested the codesandbox with the
withRedux
HOC that is working: https://codesandbox.io/s/ryxk561qp4Try clicking on the
fill results
button, then modify something in the render method of the component MyComponent, you'll see a codesandbox hot reload, then try to click onfill results
button again, it won't work.I do not know what kind of hot reloading use codesandbox, it would be interesting to know.
I think this issue can deeply interest you @markerikson and @Ephem.
I hope this use case will help us building great applications and will deliver a robust documentation on how to use dynamic reducer injection with lazy loaded component and the new Context API.
Thank you for reading,
The text was updated successfully, but these errors were encountered: