Closed stevoland closed 10 years ago
Thanks! React theoretically makes server side rendering quite easy... but it gets complicated when you start dealing with all sorts of async data loading.
I think it'd be possible to pass data to the Fluxy.start call, which would allow server-side bootstrapping of the stores when they mount. Then, React components would try to get data from the stores, which would already have the bootstrapped server data. The challenge is in getting something like react-router to work... not sure it supports server-side rendering yet. @rpflorence or @mjackson, is there a way of specifying the URL for server rendering with react-router?
@jmreidy Not currently. We definitely want to make it happen tho, just need to figure out how. I'll open an issue over at react-router so we can track progress there.
@mjackson Seems like the top level route (that takes the location
prop) could also take an initialPath
prop, that's passed to urlStore.setup(location, initialPath)
. If initialPath
is not null, urlStore
just doesn't call handlePathChange
(as it does on L39; instead, it calls updateCurrentPath(initialPath)
. Make sense?
@jmreidy Yes, it will probably be something like that. In general, I want to have a way to decouple routers from listening to the URL, so you can just pass in whatever URL you want for testing or server-side rendering. We'll get there.
I've opened an issue where we can track the work here: https://github.com/rpflorence/react-router/issues/16
Now that react-router has server side rendering, this should be fairly easy to implement. I'll look into it in the next week or so.
Now that 0.3
is out, I'd like to get a priority list for features. Most basically I think that server side rendering would just require the ability to pass data into Fluxy.start
. Depending on how stable the API is with 0.3
, I'll move onto this soon.
:+1:
Initial version of this should be landing today! I'll update this ticket when it's ready.
Looking forward to it!
I still need to add tests and document this, but server side rendering can be seen in the example now. It's actually incredibly easy to add support for it with Fluxy.
Fluxy.createStore({name: 'TodoStore', //other config})
React.renderComponentToString
, make sure to call Fluxy.start
on the server, passing it a hash of Store initial states (keyed by Store name)Fluxy.renderStateToString
Fluxy.start
, call Fluxy.bootstrap(windowKeyOfBootstrappedData)
...and that's it. Don't need to touch your Fluxy code at all - it just works.
A+
:heart: @jmreidy
Started rolling my own to get used to React/Flux, but may switch to this now. Definitely need "server-side". Doing it all pure static in Middleman, so not really a backend, just a pre-render.
@tdreyno Awesome! Let me know if you run into any problems.
I was realizing another cool benefit of the renderStateToString
approach is that you can easily serialize your entire client side app state and persist it to the backend. I'm planning on adding that to the example todomvc in the near future.
With your implementation of server rendering, how would it handle 2+ requests coming to the server at the same time? It Fluxy is a singleton and stores would contain data relevant to the user making the request, wouldn't multiple requests cause the data to become unreliable?
If User A makes a request and then User B makes a request, the stores would then contain the data relevant to User B, but if the request for User A is still processing, and requests any data from a store, it might render with User B's data, from User A's request!
Please correct me if I'm misunderstanding something, or let me know how to solve this issue, or if this is a known issue without a current solution.
Any news on that ticket? Especially @bgoldman question?
I'm going to go ahead and close this for now, as I think the current implementation is working (well enough) that future changes can come from new tickets.
@bgoldman concurrency shouldn't be an issue so long as Fluxy configuration and rendering happen within the same function. Fluxy resets all its stores whenever the state is set, so the global nature of the stores should be isolated within each function call. (Functions bodies can't be processed simultaneously in Node.) That said, if there's any async between Fluxy config and renderStateToString, there'd be a problem - so refactoring things AWAY from global / single instance configuration is a good idea.
@jmreidy there is definitely async going on between init and renderStateToString, because the data that ends up in the stores is pulled asynchronously from API calls and/or the database. I'm assuming the vast majority of Fluxy apps have async to pull data, because the vast majority of apps need to make API calls and/or get data from the database.
How would you recommend running Fluxy on the server in a way where if we have two requests come in at the same time, we still maintain data integrity on a per-request basis?
@bgoldman I think part of the issue here is that Fluxy.start
is not the best name for what this method does (in the case of server side rendering). Fluxy.start
is instantiating and setting up a new Fluxy instance every time it's called. So if there's no async between Fluxy.start
and renderStateToString
, then there shouldn't be a concurrency problem. So basically, Fluxy.start
should only be called when all the data is ready and you're rendering your response - just as you would pass data to res.render
and a Handlebars template in a traditional web app, for example. See the example here: https://github.com/jmreidy/fluxy/blob/master/examples/todomvc-flux/server.js#L58
But I do think that renderStateToString
could be moved to the Fluxy instance, which should solve any and all problems. I'll open a ticket to do that.
Hi,
This looks really good. Are you planning on implementing server side rendering at all?