Open
Description
It would seriously ease the process of building something isomorphic if componentWillMount could return a promise and that react would delay rendering until that promise is resolved. I have seen attempt of doing something like that in react-router and rrouter, however giving this responsibility to each component instead of a router module would make more sense for me.
Activity
sophiebits commentedon Jun 24, 2014
The main reason (I believe) that this doesn't exist already is that on the client side, you basically always want to show some sort of loading indicator instead of deferring rendering. (It would also make the code significantly more complex, but we can probably deal with that.)
fdecampredon commentedon Jun 25, 2014
There is 2 cases that I find hard to solve without that:
react-async solve those problems with fibers, and cache. That do the trick but in my point of view those are just hackish solutions to solve a problem that can only be solved in core.
syranide commentedon Jun 25, 2014
Color me uninformed on this subject, @fdecampredon say that
componentWillMount
is async and you don't return anything immediately, what is React supposed to render until there is, nothing? If so, why not just return nothing in render if there is no data yet? (Yeah I get server-side) Also, what should happen if props change beforecomponentWillMount
fires?Personally, it seems like it's wrong to dispatch async requests during
componentWillMount
unless the component really is an isolated black box and also implements a loading indicator. As far as I understand it, React components should not be mistaken for more conventional OOP instances. In the best case, a React component is tool for visualizing the data in props, if it's interactive then possibly also state. It's a view, not a view and model.To my ears, that sounds like the problem, React components shouldn't be the ones dispatching the async requests, you fetch all the data and when that data is ready, only then do you call
React.renderComponent
. Same solution client-side and server-side. You also get the ability to abort with an outcome of your choice if any async request fail.Feel free to dismiss me if I misunderstood something, but it seems that you're treating React components as view and model, when (it seems) they're meant as just the view.
fdecampredon commentedon Jun 25, 2014
I must admit that I did not think about all the cases ^^.
This feature would be useful only the first time we mount the top level component, and on the server, it's true that otherwise In most cast you would want to display a loader indicator.
In a way or in other you'll want that a 'top-level' component would be able to retrieve data, like it's done in the Flux sample.
In this sample things are pretty simple because retrieving the list of todo is a synchronous operation, if it was not, and in case of pre-rendering on the server, we would render a first time with no data (and loose the pre-rendered markup from server).
In the case of a simple application with one set of data displayed by one view hierarchy there is still not so much problem, you can preload data and still keep the synchronous property of your store.
Now in case of an application composed of multiple modules that you reuse across your application I would like to be able to treat those modules as separate applications that are able to 'subscribe' on different stores (that would be responsible for fetching data).
Perhaps That I get the things the wrong way but some discussion/sample around the web make me think there is something missing somewhere:
willTransitionTo
, and some discussions make me feel that nobody has come with a proper solution.mjackson commentedon Jun 26, 2014
@fdecampredon To be clear, the purpose of
willTransitionTo
in react-nested-router is not for loading data, specifically because returning a promise from that method will indeed block rendering new UI, which you don't want to do unless you absolutely have to.syranide commentedon Jun 26, 2014
@fdecampredon Everyone is still trying to figure things out, so it wouldn't surprise me if no one has a definitive answer. But I'm guessing the devs at Facebook must've run into this themselves a few times.
tobice commentedon Oct 2, 2014
Any update on this? I've just started exploring React and I immediately run into this. Many people recommend React as a go to solution for building isomorphic apps, but as long as this is not solved I think it simply can't get the job done.
If this is true then React is nothing more than a slightly different templating solution / view layer. And that would be a shame because there is such a potential. I really understand @fdecampredon when he mentions those complex applications composed of multiple modules. React would be perfect for this.
I don't think that this approach would mean treating a component as view and model. If you look at the Flux architecture, they think of React components as of controller-views that not only display data (from stores) but also invoke actions based on user interactions. And the actions then update the stores (= model). To me it sounds just like an obvious MVC architecture.
The problem is with the initial action that populates the store. It's fairly simple on the client side where the action can be invoked from the
componentDidMount()
method as recommended. On the server side on the other hand, we really need some special place and some kind mechanism that would delay the rendering until the action is finished and the stores are populated.At this moment, it seems to me that the only way is React-async/Fibers + Flux. The nice thing about Flux is that we don't need some artificial cache to transport component states from the server to the client (like it's done in the original react-async example), we can simply initialize the stores and then send them to the client with the html markup (see this example).
But this solution is indeed hackish.
mridgway commentedon Oct 30, 2014
I don't think it necessarily needs to be componentWillMount that is async; I'm not even sure it needs to be a lifecycle event. The real issue is that on the server side there is no way to analyze the component tree until after everything has been rendered to a string.
My ideal solution to solve this would be to allow "rendering" that would just build the component tree, then we would be able to traverse the tree to find components that need additional data, allow us to asynchronously load more data and "re-render" that components subtree, and then once we are ready for flushing the markup, allow us to convert that tree to a string.
This replicates what we're able to do in the browser: have a virtual DOM that we can re-render as we want. The difference is that in the browser DOM updates can be implicit. On the server we need to be explicit about when we render to a string so that we can perform updates to the virtual DOM based on async data.
koistya commentedon Nov 11, 2014
Yep, that would be good. Currently, rendering component twice on a server-side can be used as a workaround.
mridgway commentedon Feb 27, 2015
I want to reference react-nexus as an example of what I'd want to be supported within React. It's essentially a rewrite of how
mountComponent
works except that it builds out the component tree without actually mounting it to the DOM or writing out a string. This allows you to traverse the component tree and fire off asynchronous methods while the tree is being built up. The issue with this implementation as it is, is that it throws away that first tree and then callsReact.renderToString
anyway, whereas it would be nice to take that pre-render tree and render/mount it.I'm willing to work on this within core, but would need some pointers. I think one of the requirements is making
ReactContext
not globally referenced so that async wouldn't cause issues. Are there other globals that might run into issues with this as well?gaearon commentedon Feb 27, 2015
@mridgway If I'm not mistaken global
ReactContext
might be a compat thing and will go away in 0.14. But I might be wrong.mridgway commentedon Feb 27, 2015
@gaearon Yeah, that's the sense I got from the withContext deprecation.
158 remaining items
gaearon commentedon Nov 29, 2018
FYI we’ve started work on this.
https://reactjs.org/blog/2018/11/27/react-16-roadmap.html#suspense-for-server-rendering
steve-taylor commentedon Nov 29, 2018
Awesome @gaearon!
@davnicwil
react-baconjs
supports unlimited depth.ivan7237d commentedon Dec 10, 2018
@gaearon I wonder if this would make possible support for observables in create-subscription, so that I can convert an observable firing JSX into a react component?
I'd love to have this feature for two reasons. First, in my app the state is stored in a web worker. So while retrieving bits of that state which are required by the component is an async operation, it takes like 5ms and it doesn't make sense for React to render anything while waiting for the data. Second, right now there's no universal way to convert an observable to a component: if your observable emits the first value synchronously, then what you do is subscribe to get that value, then unsub, then subscribe again to listen for changes (that's the Replay subject example in create-observable docs). And if it emits the first value asynchronously, then you initially render null and listen for changes.
davnicwil commentedon Apr 10, 2019
@steve-taylor react-frontload now also supports unlimited depth of component nesting, with the
1.0.7
release.Hope this library is useful for some people landing on this thread - if you're looking for an async data loading solution that works on client / server render, with very minimal integration effort, you should check it out.
RyanRoll commentedon Aug 21, 2019
We had encountered this problem before as our app was built with React Hooks, and then we created a package react-use-api to solve it, which is a custom hook that fetches API data and supports SSR. I hope the package can help people in need.
However, we are still looking forward to waiting for an official solution, Just like react-frontload says, there's no built-in way to wait around for async data loading to happen once render begins currently.
gaearon commentedon Dec 21, 2020
We've made more progress on this.
https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html
wmertens commentedon Dec 23, 2020
Summary of my understanding of Server Components as they relate to this topic:
You'd have an SSR setup that renders a root with Server Components. A request would be rendered and result in a stream of elements, depending on the Suspense mechanism in the Server Components.
The SSR can convert this to HTML and stream it to the client, pausing the stream every time it encounters a placeholder. The end result is SSR only requiring a single pass and providing bytes to the client as soon as they are available 🎉.
As you can see, Server Components are crucial to make this work. This means that if you want your app to work like before, as an SPA without further Server Components calls, you need to return Client Components that get their initial state from the SSR and perform data fetches on state changes.
gaearon commentedon Mar 24, 2021
Here’s the other part that does the actual streaming SSR (work in progress, not done yet). In this world Server Components is where you do data fetching, and then the new HTML renderer turns that stream into an HTML stream that can progressively render as soon as we have some content — even before all data has loaded.
#20970
gaearon commentedon Apr 1, 2021
Today, we're announcing React Labs — a new video series with technical deep dives with the React team members. Our first video is a Server Components Architecture Q&A deep dive. We hope you enjoy it! (It's very related to the topic in this thread.)
gaearon commentedon Jun 9, 2021
Yesterday, we published The Plan for React 18.
tldr:
React 18 will include a lot of foundational work for Suspense. This includes a brand new streaming server renderer which uses the
<Suspense>
boundaries to stream HTML and to hydrate the page in chunks, dramatically improving responsiveness.gaearon commentedon Mar 29, 2022
React 18 is out with the new streaming renderer.
In principle it already supports asynchronous data fetching (producing rendering results as a stream). However, there are still questions about how exactly to transfer data for hydration to the client. So we shouldn't close this yet. The architecture is there but it's not quite usable yet. (However, if you're a framework author, you might be able to start tinkering with it.)
insaaFusion commentedon Dec 26, 2022
Use useLayoutEffect hook