-
Notifications
You must be signed in to change notification settings - Fork 114
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
Issue with server rendering and HoC #170
Comments
This is the branch I'm using on my own right now. |
im not sure if the following is the direct cause of your issue, but stores shouldn't fetch, do async or side-effecty things (that includes firing actions). try putting your async/fetching in actions and passing those results to stores. |
@burabure Alright, might be an issue with the way I'm doing it then. I'm not sure about that philosophy'though. I've seen both implemented ways a lot in Flux-ies. Anyway, if the stores don't fire actions, it means whether you need actions to know about store state (you don't want to be fetching data constantly for no reason) OR then every component needing the data needs to check if the data is already fetched, and then fire the actions if it's not. If your stores don't do fire actions, you need to have another layer of functions (like the routerWillRun that checks if the data is fetched, and fires actions if it's not.) And you get to have a lot of code repitition that way. And it also means that you need the top handler to know about all of his child, instead of having components that needs data be connected to the store (with the HoC) and ask for his own data. |
take a look at this presentation https://speakerdeck.com/jmorrell/jsconf-uy-flux-those-who-forget-the-past-dot-dot-dot-1 also here's an awesome checklist by Dan: |
@burabure Alright, I can refactor the stores to be totally syncrhonous. But where would you put the fireing of actions to fetch the data.
I'm kind of lost on how to do it. I've been trying to figure it out in the past days, but fireing actions from the store was the simplest way I found to make it work both server-side and client side. Any comp just ask for data, and it will eventually receive it. All you needed to change on the server was the actions (because they need to use a different api so that they fetch data from database directly and not from ajax requests), and you have to render twice. First time, the components auto-register the data they need, once it's loaded you render and send to client. |
I ran into this with Reflux but according to the author it's OK for a store to fire an action, at least sometimes :p |
@dozoisch I don't know what would be best for your app, but there's plenty of places you can fire the action on components; getInitialState or constructor, componentWillMount... flux is very new, and the community is starting to figure where the footguns are; firing actions from stores is one because it can cause cascading updates very easily. |
@burabure I guess that makes sense, I can change where actions fireing happens. There is still one issue though (that is the same). The connectToStore register callbacks before the component is mounted. (It registers the stores callback on initialization.) And if I'm not mistaken, renderToString will initialize the components, but will never mount them. So if an actions completes, juste after a renderToString, the callback will fire setState on a non-mounted component. Which shouldn't be possible? I'll do some more testing to see the exact lifecycle called when rendering with toString |
from the react docs
so it seems to me that it shouldn't be an issue. but if you find any problems just post back |
The error happens server side not client-side. It happens after the render to string, once the actions fnishes and updates the stores. The store tries to setState on a component that is not-mounted (but has been rendered with |
is difficult to be certain of where the issue is occurring without looking at the project itself. could you post the offending component code? |
ok, I found the cause.
so I would move the data fetching to a helper-like js file on /utils and call that on actions and before rendering the component on the server. |
Alright, I'll take a look at this. My goal was to be able to call renderToString first (which would fire the actions), I wait until actions have completed then call another renderToString with all the data now in the stores. Maybe I can disable the change event from the store when on server or something! I'll get back to you, thanks for helping. |
I am glad I was able to help. Let me know how you solve it at the end =) |
@burabure I've did some more investigations and connectToStore adds the That means that if I fire actions at initialization, or at willMount it will do the exact same issue. That I have right now. Solution I can see is to change the moment listeners are added. At initialization, create a listeners map which is only "added" at ex: // instead of store.on("change", listener); you do:
this.listenersToAdd.push(() = > {
store.on("change", listener);
});
then:
componentDidMount() {
for (listenerToAdd of this.listenersToAdd) {
listenerToAdd();
}
delete this.listenersToAdd; // or just this.listenersToAdd = [];
} This way, stores won't get a setState event when not mounted. Because right now, |
@burabure Any thoughts on that? |
Alright, I don't know if the issue is on the way I'm doing things, but I have a weird issue when using HoC on server side rendering.
My stores fetch their data automatically when asked for
ex:
store.getUpcomingEvents()
will return the events if they are already fetched, or will create the action to fetch them.So when rendering server-side, I just do
renderToString
first. This create the actions needed, and once all the actions are finished, I do a secondrenderToString
and the view then gets rendered with all data needed.When the store dispatches the change event from loading, this function gets called:
https://github.com/acdlite/flummox/blob/master/src/addons/reactComponentMethods.js#L185-L190
The problem is that the setState is called on a non-mounted component which creates an error afterwards. That error then stops the dispatching and "everything breaks".
The only fix I could see was to check whether the component was mounted before calling the set state. And I'm using a custom
this.mounted
instead ofthis.isMounted()
becauseisMounted
is deprecated...So
I don't know if there is another way of doing it?
The text was updated successfully, but these errors were encountered: