React: Support asynchronous server rendering (waiting for data before rendering)

Created on 24 Jun 2014  ·  139Comments  ·  Source: facebook/react

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.

Component API Server Rendering Backlog Feature Request

Most helpful comment

A few months ago I gave a talk at JSConf Iceland that describes the upcoming async rendering features in React (see the second part): https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html. This is about client-side data fetching.

Now @acdlite gave a talk about how the same concepts can apply to enable asynchronously waiting for data on the server in React components, and progressively flushing down the markup as it’s ready: https://www.youtube.com/watch?v=z-6JC0_cOns

Hope you’ll enjoy watching these talks! I think that in a year or so we might be able to close out this issue and have an official strategy for this.

All 139 comments

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.)

There is 2 cases that I find hard to solve without that:

  • On the server side, if you want to fetch data before rendering you can't delegate data retrieval to components since you don't have the information of which component will be rendered
  • On the client side the first time you mount your application after receiving pre-rendered html, even if you have some sort of cache from data retrieved on the server, you might want to use async method to retrieve those data, and that would prevent react from reusing the html.

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.

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 before componentWillMount 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.

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 before componentWillMount fires?

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.

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.

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:

  • In some sample it seems to me that @petehunt tried to achieve something similar.
  • react-nested-router promote some similar mechanism in willTransitionTo, and some discussions make me feel that nobody has come with a proper solution.
  • RRouter also provides some kind of mechanism to prefetch data as the component is being rendered/mounted.
  • and finally react-async like I said earlier.

@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.

@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.

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.

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.

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_.

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.

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. — @mridgway

Yep, that would be good. Currently, rendering component twice on a server-side can be used as a workaround.

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 calls React.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?

@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.

@gaearon Yeah, that's the sense I got from the withContext deprecation.

:+1: Using react-router for this ATM. @mridgway's approach sounds very reasonable.

A slightly different take on this issue is how to handle asynchronous loading of code chunks produced by a bundler (such as webpack).

As discussed in this ticket - https://github.com/rackt/react-router/issues/1402 - the issue with async rendering support is the initial render appears to be null as the relevant chunks haven't yet loaded in the first render pass, resulting in a <noscript> at the root of the DOM and a checksum fail. Everything falls into place quickly afterwards, but it does result in a flicker in the UI when working locally and worse in the field, especially if the chunks to be downloaded are of a reasonable size (say > 30KB)

The ability to split up big apps into multiple chunks is important to us and having solved the data fetching issue (we used react-router and nested routes which can be traversed prior to rendering on the server to fetch data dependencies) this is the last piece of the puzzle blocking us from moving fully to a React solution for our front-end.

@anatomic That's not React's responsibility, it's your job to chunk appropriately and defer rendering until all necessary chunks has been loaded. To put it differently, if one of your components has a dependency on some external library, it's obviously your problem to satisify before trying to use it, React couldn't do it even if it tried, so the same applies across the board.

Feel free to implement alternative strategies that may suit you better, say <WaitFor for={MyAsyncLoadedCompSignal} until={...} then={() => <MyAsyncLoadedComp ... />} />. But these are inherently opinionated and not something React should or even needs to offer, so it's best left to the community.

It's better to keep async stuff outside the scope of React components, here is an example:

import React from 'react';
import Layout from './components/Layout';
import NotFoundPage from './components/NotFoundPage';
import ErrorPage from './components/ErrorPage';

const routes = {

  '/': () => new Promise(resolve => {
    require(['./components/HomePage'], HomePage => { // Webpack's script loader
      resolve(<Layout><HomePage /></Layout>);
    });
  }),

  '/about': () => new Promise(resolve => {
    require(['./components/AboutPage'], AboutPage => { // Webpack's script loader
      resolve(<Layout><AboutPage /></Layout>);
    });
  })

};

const container = document.getElementById('app');

async function render() {
  try {
    const path = window.location.hash.substr(1) || '/';
    const route = routes[path];
    const component = route ? await route() : <NotFoundPage />;
    React.render(component, container);
  } catch (err) {
    React.render(<ErrorPage error={err} />, container);
  }
}

window.addEventListener('hashchange', () => render());
render();

See Webpack Code Splitting, React.js Routing from Scratch and react-routing (coming soon)

@syranide I'll keep working away at it, but I don't think it's as binary as you've put it above. We are using react-router so that may introduce some issues to the mix as the router is a component rather than sitting outside the React environment.

If we did the <WaitFor ... /> approach, surely we'll still get a different DOM on the first render which will still cause the flicker/disappearance of content?

If we did the approach, surely we'll still get a different DOM on the first render which will still cause the flicker/disappearance of content?

If you don't want flicker (some do) it's simply a matter of waiting for all the chunks you depend on to have loaded before rendering, webpack provides this out-of-the-box with require.resolve.

PS. Yes, react-router and whatever else you're using surely complicates the solution, but it's still not React's problem to solve.

If you don't want flicker (some do) it's simply a matter of waiting for all the chunks you depend on to have loaded before rendering, webpack provides this out-of-the-box with require.resolve.

I'll look into that, my understanding of require.resolve was that it was a synchronous lookup of a module's id and didn't involve a trip to the server? We're using require.ensure to manage our chunk loading.

Looking at our code again I think we can circumnavigate the problem by making react-router think it's rendering on the server but then following the standard client-side approach:

const history = new BrowserHistory();

if (typeof history.setup === "function") {
    history.setup();
}

Router.run(routes, history.location, (err, initialState, transition) => {
    React.render(<Provider redux={redux}>{() => <Router key="ta-app" history={history} children={routes} />}</Provider>, document.getElementById('ta-app'));
});

I'll look into that, my understanding of require.resolve was that it was a synchronous lookup of a module's id and didn't involve a trip to the server? We're using require.ensure to manage our chunk loading.

Sorry, yes I meant require.ensure. The callback is executed only when all the dependencies are satisfied, so it's a matter of just putting render/setState inside of it.

Ok, that's kind of how we were doing it, thanks for your replies. This feels like something that needs to be addressed in react-router so I'll carry on the discussion there - sorry if this has been the wrong place to have this conversation!

You are right that the require.ensure is the way to go, I guess our ultimate issue was that it should be linked to the route currently being visited so is directly tied to the router. With react-router being component based that ties it to the render tree. Without my hack above we're left fighting a way to view the tree before everything is loaded async (or duplicating the routing logic to allow for relevant chunks to be loaded at the top level).

You are right that the require.ensure is the way to go, I guess our ultimate issue was that it should be linked to the route currently being visited so is directly tied to the router. With react-router being component based that ties it to the render tree. Without my hack above we're left fighting a way to view the tree before everything is loaded async (or duplicating the routing logic to allow for relevant chunks to be loaded at the top level).

I'm not intimately familiar with react-router, but I still imagine it simply being a case of setRoute(...) => require.ensure([], function() { require(...); setRoute(...); }) which really isn't practical so you introduce another level of indirection. A map of routes and the async require.ensure loader for each. Write a helper function asyncSetRoute(...) { loadRoute(route, function() { setRoute(...); }}, now you call asyncSetRoute instead and it will defer updating the router until everything is ready.

Pseudo-code and kind of generic, but that seems like the overall approach to me. Maybe react-router should provide this, maybe not... maybe it's ideally provided as an external helper, I'm not sure.

So after hours of research, I'm just now confirming that server side rendering is _impossible_ unless you feed everything from the top down (?).

Possible short term solutions:
A. Pre-fill a store and make server side loading synchronous

B. Feed everything from the top as one data input after async fetching your one data object.

re: 'A'. This wont work unless you already know what your render structure will look like. I need to render it in order to know my various collections/models/api dependencies. Also, how do I have the fetching be async on the client, but sync on the server, without having two different APIs?

re: 'B'. Basically the same problem as above. Are people having to make little dependency JSONs to go with each of their routes?

Are there any other short term solutions while we wait for a React supported solution? Any user land forks or plugins? https://www.npmjs.com/package/react-async ?

@NickStefan

I don't understand the problem. :-(

  1. Use Flux or Flux-like container (Alt, Redux, Flummox, etc) where stores aren't singletons.
  2. Define static methods like fetchData on your route handlers that return promises.
  3. On server, match route to components, grab fetchData from them and wait for them to complete before rendering. This will prefill your Flux or Redux store instance. Note that store instance is not a singleton—it's bound to a particular request, so requests stay isolated.
  4. When the promises are ready, render synchronously with the store instance you just prefilled.

Here's a good tutorial for Redux describing this approach: https://medium.com/@bananaoomarang/handcrafting-an-isomorphic-redux-application-with-love-40ada4468af4

@gaearon I apologize if I confused you. Thank you for response. From your list, it sounds like I am correct in assuming the solution to server data dependency is to only ever define data needs at your root component (static methods / the article you linked to). If your data dependencies are defined at the root, it's much easier to pre-fill stores etc.

This is good flux practice, but isn't it potentially limiting? If I add a small component at the bottom of your view tree that needs some very different data, I then need to go edit the data dependencies at the root.

What I'm asking for is a way for deeply nested components to define asynchronous data needs.

If I have to add their needs to the root component, aren't I coupling the root to that one sub components needs?

@NickStefan with react-routing, for example, the async data fetching looks like this:

import Router from 'react-routing/lib/Router';
import http from './core/http';

const router = new Router(on => {
  on('/products', async () => <ProductList />);
  on('/products/:id', async (state) => {
    const data = await http.get(`/api/products/${state.params.id`);
    return data && <Product {...data} />;
  });
});

await router.dispatch('/products/123', component => React.render(component, document.body));

Those solutions work but only because all data pre-fetching is bound to the router. That is not a problem in most cases (it makes sense, URL defines what should be on the page and therefore what data is needed) but in general it's a limitation. You will never be able to create a standalone reusable component (i. e. Twitter stream, comments, calendar) that would handle everything by itself and all you had to do was just insert it into component hierarchy. The only way I've come across that makes this possible is react-async but that's pretty much a hack.

I suppose that React components are simply not intended to be used this way, they are still more views than _controller_-views. Probably a completely new library will have to emerge on the foundation of React.

My dream is that one day we'll be able to write a complete CMS using React, something like Wordpress, Drupal or Modx. But instead of HTML/PHP snippets we'll be composing the website from React components.

@NickStefan

From your list, it sounds like I am correct in assuming the solution to server data dependency is to only ever define data needs at your root component (static methods / the article you linked to). If your data dependencies are defined at the root, it's much easier to pre-fill stores etc.

If I have to add their needs to the root component, aren't I coupling the root to that one sub components needs?

Not exactly at the root—at route handler level. There may be many route handlers in your app. Moreover, libraries like React Router support nested route handlers. This means your nested route handler can define a dependency, and the router match will contain an array of matched hierarchical route handlers, so you can Promise.all them. Does this make sense?

It's not as granular as “every component can declare a dependency” but I've found that in most cases limiting data fetching to route handlers (top and nested ones) is all I want. I have pure components below that accept data via props so they don't even _know_ it's being fetched. It makes sense that they can't request it.

The “every component can declare a dependency” approach isn't practical unless you have some sort of request batching solution. Imagine if <User> declares that it needs an API call, and now you render a list of 100 <User>s—would you want to wait for 100 requests? This kind of data fetching requirement granularity only works when you have a request batching solution. If that suits you, Relay is exactly that. But you'd need a special backend for it.

@NickStefan We don't currently support per-component async fetching. We'd like to add it. This issue tracks our progress, though no one is actively working on it and it will take major restructuring so it will be a while.

@gaearon

The “every component can declare a dependency” approach isn't practical unless you have some sort of request batching solution.

After some more thought on this, I agree with you. What I was seeking isn't actually practical.

I originally had the thought that even your 100 example would be okay with team discipline (ie just make a <UsersContainer> that does 1 request for all 100). But that's not "people-scalable" to merely have a convention. Its probably for the best to enforce all the dependencies to the root or the router. Even Relay sort of forces you to declare dependencies at the Root with its three different containers (RelayContainer, RelayRootContainer, RelayRouter etc). It kind of proves the point that the only way is to essentially "hoist" your dependency declarations up the tree.

Hi there!
Is there any updates on this?

+1

I maintain that if you really think about this, you don't want to do this. I originally thought I wanted React to do async rendering. But others in this thread have convinced me otherwise.

Even in Relay, you basically have to "hoist" your dependencies up the tree with the root container declarations, relay containers etc. Synchronous rendering is the way to go.

Asynchronous rendering can be a nightmare. I speak from experience from working on a company codebase with backbone that was hacked to do individual updates in request animation frames.

Agreed. I used to think that we needed this, but it is actually backwards to have the view specify what data to load. The view is a function of the application state, which is itself a function of the request (and possibly the user's state, if there is a session). This is what React is all about; allowing components to specify what data should be loaded goes against the "one way data flow" idea, IMO.

it is actually backwards to have the view specify what data to load.

I'm not entirely sure this is true. Sometimes, the component is the only thing that knows what data to load. For instance, suppose you have an expandable tree view that allows a user to browse a massive graph of nodes - it is impossible to know in advance what data needs to be loaded; only the component can figure that out.

Regardless, this discussion might become much more relevant if we pursue the idea of running React code within a web worker (#3092), where async is required to communicate across the bridge.

In the example of a large tree view, if I really wanted to be able to render it with a path already open on the server side, then I would add that path to the URL structure. If there were several complex components like this, then I would represent their states with GET parameters. This way, those components get all of the benefits of SSR: they are crawlable, can be navigated using history, users can share links to a node within them, etc. Now, we also have a way for the server to determine what data needs to be fetched in order to render a response.

update My bad mistaking a graph for a tree, but I still feel that the state of a user's view of that graph should be represented by URL structure. Also, didn't realize that you actually work on React. If you are working on some framework for integrating a data layer with the view isomorphically, that's awesome. But I think we can agree that that goes beyond the domain of the view, and that React should not take on the role of a full stack controller.

Didn't read the whole thread so sorry if this was discussed already.

One thing that would really help would be if there was a react-dom/server method that would just "start/instantiate" a component and fire lifecycle methods but let the developer decide when he is ready to render the component to an html string. For example, the developer could use setTimeout or something more reliable to wait for async methods to complete.

This is the "hack" I'm using with redux at the moment to achieve this:

  // start/instantiate component
  // fires componentWillMount methods which fetch async data
  ReactDOM.renderToString(rootEle)

  // all my async methods increment a `wait` counter 
  // and decrement it when they resolve
  const unsubscribe = store.subscribe(() => {
    const state = store.getState()
    // as a result, when there are no more pending promises, the wait counter is 0
    if (state.wait === 0) {
      unsubscribe()
      // all the data is now in our redux store
      // so we can render the element synchronously
      const html = ReactDOM.renderToString(rootEle)
      res.send(html)
    }
  })

The problem with this approach is that the second ReactDOM.renderToString fires all the componentWillMount methods again which results in unnecessary data fetching.

Hey guys! is this something currently being worked on? I think this issue is growing in importance. I've recently made a library that sort of extends react redux's connect to a dataConnect where you can also specify the container data requirements. These data requirements are then bundled runtime and queried with GraphQL in a single request. I think this is the future of data specifications as it promotes composability and isolation and also ensures a more performant fetching. (all concepts seen on Relay)

The problem with the above is server side rendering. Since I can't statically analyze which data requirements I'll end up with, currently, I'd need to render one time to get the bundle to query from the DB, hidrate the redux store and then re render to get the final string. The issue is similar to @olalonde's one.

Would be fantastic to able to trigger actions and updates to the react elements tree and get the DOM string result on demand. Here's how I picture it:

const virtualTree = ReactDOM.renderVirtual(rootEle);

// get the bundled query from redux store for example
const bundle = store.getState().bundle;

// Fetch the data according to the bundle
const data = fetchDataSomehow(bundle);

// hydrate store
store.dispatch({type: 'hydrate', data});
// components that should update should be marked on the virtual tree as 'dirty'

virtualTree.update(); // this would only update the components that needed update

const domString = virtualTree.renderToString(); // final result

Other option is to simply let it update at will like it would be on the client side, having all the hooks present and working such as didMount. But instead of mutating DOM it would just mutate the virtual dom representation, and render to string on demand as well.

What do you guys think? Something to consider or I'm seeing it completely wrong?

Hi all. I've been subscribed to this issue for a year or so now. Back then, I thought that I needed to be able to specify the data that should be loaded from within components, because components were my primary unit of modularity. This issue was really important to me, and I thought that for sure it would get resolved in the next version of React.

Since then, I have developed a much deeper respect for the ideals behind REST/HATEOS, because of the large scale simplicity that emerges in a system of applications (browsers, crawlers, application servers, proxies, CDNs, etc) when its guiding principles are followed. As it relates to this issue, _the URL should be the one true representation of the application state_. It, and only it, should determine what information is required to service a request. The view layer, React, should not be determining this; it should be constructed based on the data. The view is a function of the data, and the data is a function of the URL.

I have hesitated to throw this out there in the past, because I keep hearing that this is a nice idea, but that the real world is just too complex for this to work. And occasionally, I hear of examples that make me take a step back, and wonder if I am being too pedantic, or too idealistic. But as I mull over these examples, I inevitably find a reasonable way to represent the application state in the URL.

  • Does your state have independently varying parameters? Represent them as separate query parameters.
  • Is your state (or part of it) too big to fit into a URL? Name it and store it in an immutable datastore. Refer to it by name / ID.
  • Is your state changing so fast that you just can't store all of it forever? Congrats, you have legit big data, spring for storage and start thinking about clever stuff to do with it. Or, you can shy away, and and just mutate your data with UPDATE queries, and accept that you cannot forever-cache all the things later (*).
  • Do you have views that are different for different users, but served at the same URL, e.g. a personalized home page? Navigate upon user identification to a URL that includes the user's ID.
  • Are you building over an older application, where you do not have the option to break the old URL structure? That's painful, I'm in the same boat. Redirect the old URL structure to a well architected URL structure, translating session data (or whatever) to URL path segments and parameters.
  • Do you have little or no control over the architecture of your application? That is not the case that React was designed for, and we don't want React getting mangled to make it fit into something like a mutually compatible Wordpress / Magnolia / Umbraco architecture.

What do you get for all of that work, that you would not have otherwise had?

  • The ability for one user to bring another user to the same place as them in the application, by sharing a URL.
  • The ability to navigate the application using all of the tools that the browser provides. The standard client is in its element.
  • The ability to offer complex pagination in a way that is simple for the client to follow: a next link in a response. The FB graph API is a great example of this.
  • A detailed graph of your user's workflows in Google Analytics.
  • The option of constructing said graph yourself from nothing but request logs.
  • An escape from the star-route of chaos: Instead of matching all requests as an app.get("*", theOneTrueClientonaserverEntryPoint), you get to use your server application framework as it was intended. You can return correct HTTP status codes from requests, instead of 200 OK\n\n{status: "error"}. The star route is enticing, but it leads to madness.

So, now that React, our star tool, isn't controlling the operation, how do we get our data? How do we know what components to render?

  1. Route to a data access function and fetch data for the relevant request parameters. Repeat until you have parsed the whole URL and have a complete context object.
  2. Transform the context into the most simple response object possible, as if you were going respond to an API request. Are you serving an API request? Then you're done and DRY.
  3. Pass that minimally complex, but possibly large, object to the top level component. From here, it's React component composition all the way down.
  4. Render to string, respond. Let your CDN know that it can cache this forever (* unless you sacrificed this option above), because CDN identify by URLs, and all of your states have a URL. Sure, CDNs don't have infinite storage, but they do prioritize.

I don't mean to troll here, but I do feel strongly that the core theme of the requests in this issue are misguided, and that React should not implement anything to accommodate it, at least not for the reasons that I have seen here over the past year. Some aspects of good application architecture are not obvious, and web is especially hard to get right. We should learn from and respect the wisdom of our ancestors, who built the Internet and the Web, instead of sacrificing elegance for the sake of comfort.

That is what makes React great: It is the view. The best view. Only the view. λ

Will have to disagree with you @d4goxn. I'm not trying to make React more than a view layer, and routing is important but definitely not enough to specify all data requirements. By specifying data requirements at a component/container level you're not making React more than a view layer. This just provides you a much better isolation and workflow for your app. It's not just a simplification of the work but a need for a big application. Imagine my app has 30 routes and I want to add a user profile component on each one. Following a route alternative where all the data requirements are specified for each, you'd have to go through the 30 routes to add that data dependency. When with if you specify your data needs in a container for that component, you just have to add the component where you want. It's plug and play. Not only this but the query for all components data dependencies can be optimized. Relay is a good example of this, and the talks about it explains this much better than me.

I have much respect for old wisdom, but that shouldn't be a limit for evolution and creating new standards, that's the way I see it at least.

My proposal is basically to not change React, but have a 'virtual only' way of altering the dom/components tree, basically a React that can be 'run' on server side, which I think is pretty simple to do (just block actions to alter the DOM). You can still have caching and have a CDN in place. With the growing dynamics of sites and applications nowadays static caching will tend to reduce but that's another topic 😄

If the view specifies dependencies on data, then you will need some way of optimizing the dependency graph and transforming it into a minimal number of queries; you cannot prepare the data before constructing the view, although you could split it into two phases, which is what I understand the plan to be in this thread. Take a collection of moderately complex components that would each have a query of their own, for example; perhaps they are not all instances of the same component, and there isn't a pattern that could be collapsed into a single query. I suppose this is what GraphQL is tackling. You will still need to implement or integrate GQL servers for each of your datastores. Sorting out which parts of the optimized GQL query should be handled by which datastore sounds pretty complex, but then my proposition has some of that complexity too.

In the example, where there are a large number of routes all needing the same data, I actually would not see that as a reason to exclude the identifier for that data source from the URL. I would mount a small data fetching middleware module fairly close to the root of the stack, which would attach that user object to a context and then pass the context along to more middleware, on its way to an end route handler. The root React component might not care about that particular part of the context, but it would pass it to the next level of children who might about it, or have descendants of their own that care. If this does introduce unreasonably complex or deep wiring, then something like a Flux store might be called for, but that is a big topic on its own.

Separation and isolation: I feel your pain there. In my proposal, we have two very different systems, transforming data from a form that is optimized for storage and retrieval, to a form that is optimized for abstract simplicity. Then my view is transforming that into a form that suits it, as it is passed down the component hierarchy. Keeping those two systems loosely coupled while adding a feature that requires additions to both systems is not what I would call hard, but it is also not the path of least resistance. The mental switch between programming for a data store and programming for a dynamic UI is real. We used to have separate backend and frontend developers, and HTTP served as the interface between these two paradigms. Now I am trying to internalize it into the one application, and you are trying delegate it.

I am not convinced that the increasing complexity and activity within applications precludes the client state from being represented by a very small object, that references a much larger data set on the server. Consider a massive multiplayer first person shooter: there is a lot happening fast, and you want to transmit the minimum amount of information necessary from the client to the game host/server. How small could you get that? A map of all input states; a timestamp + uncertainty range, a ~110 bit field for the keyboard, and a few dozen bytes for the mouse / joystick and VR headset orientation. The client would be predicting, optimistically rendering and physic-ing, and the server would be deriving a huge amount of information from the client's small state and state history, and returning a fairly large amount of data to correct and update all of the clients (all the same params for all nearby agents, asset pushes), but, that stream of client requests just might still fit comfortably into 2KB requests. And that might be a boon for the application architecture.

I won't ask you to educate me on Relay and GraphQL; I have only superficially explored them, before their APIs reached a stable version (are they locked down now?) If you are still convinced that using components to select GraphQL schemas, which specify data dependencies, which determines what actual data needs to be fetched, is a good plan, then maybe it is time I took another look at them. I have some hard questions about that architecture, but I'm about to go way off topic.

:beers:

PS I didn't mean to suggest that HTTP would be a good communication protocol for an MMOFPS

@d4goxn I completely understand your hesitation and skepticism about this. I never thought about this until starting to work with GraphQL and later the introduction of Relay's concepts. I really recommend you to give it a look. And implementing GraphQL in a new or existing server is not as difficult as you might picture, even if you have multiple data stores. Not wanting to go off topic as well, but this is an important discussion.

I believe that this level of abstraction is the way to go. I've been using it on Relax CMS and the workflow and isolation is a bliss to work with. Not only that but the data requested is not more, nor less what the ui needs, and that's made automatically by collecting which data each component needs and merging it. This is done by Relate http://relax.github.io/relate/how-it-works.html if you're interested in checking. With this I can also include any component anywhere in my application and be sure that it will work as an independent block of my application.

The only thing still to figure out is the server side rendering. After going through react's source code I believe there might be already a solution as I described, if not I could work on a solution if someone from the react team agrees with this.

@d4goxn I will also dare to argue with you :) Your original post contains a statement that the view is a function of the data, and the data is a function of the URL. I wouldn't call this exactly revealing. It applies pretty much to any website or any web application which is not completely random (there is a question whether for example the state of open dialog windows should be also part of the URL). As we all had math at school, we know that function can be composed. So the actual statement might be that what you see on the screen is a function of the URL. Again, nothing really revealing, it's just a formalization of the obvious.

For me, the main question is how to construct such a function.

The approach you suggest feels very similar to the good old server-side MVC applications (e.g. Spring MVC is a good example). The current URL activates the corresponding controller method which _does the business logic_. It fetches all required data and passes them to the view. My problem with this is following: When you look at the generated web page, it's some kind of hierarchy of components (not necessarily React components). What you have to do is to create or generate the hierarchy from the URL. But you have to do it twice! First, you need to decode the hierarchy in the controller to know what data you need to fetch, and second you need to decode the hierarchy of the view to... well... render the actual view. I don't think it's a very _DRY_ approach.

I'm not that familiar with Spring MVC but I use very often another MVC framework (PHP framework called Nette) which addresses this problem in a very similar way to how I would like to use React. This framework also supports components. The idea is that for each component (e.g. a form) you define a factory in your code which is responsible for instantiating the component and especially for _loading all necessary data_. Such a component is then possible to be included anywhere in the view. So as you write the HTML code and create the _view hierarchy_, you can simply insert a component and the underlying factory takes care of necessary initialization. The component behaves like a small independent controller, it has its own life cycle, it handles its dependencies and it can be even parametrized from the view which increases its re-usability.

I have been using this approach with React on client-side as well and it seems very viable. The React components have been from the beginning denoted as _controller-views_ and that is how I use them. I have my _controller_ components that are responsible for data fetching and then I have my _view_ components that care only about the visuals. The whole page is composed from components of both types. They are nicely decoupled and easily re-usable.

My application is not isomorphic (or universal as they call it today) as I didn't need it but the stack I'm using should be capable of that (and I believe that apart from Relay which is still experimental, this stack walked the longest path in this matter). FYI, this is how it looks like:

  • The core tool is react-router. It allows to hook asynchronous data request on each URL and it works both client-side and server-side. Formally speaking, this approach suffers from the problem I mentioned earlier. Those _controller_ components are not possible. But what matters here is the design of react-router. It allows to define both the _data-hierarchy_ and the _view/component hierarchy_ in the same place and the actual route definitions are also hierarchical. It feels very _React-like_.
  • The whole state (the data) is handled with redux. Besides all other advantages, it keeps the whole state in a single object which means its very simple and natural to create the object on server and send it to the client. Also thanks to the connect() approach, it's not necessary to pass all the data from the top level down using props (that would be absolutely crazy considering the current size of my application).
  • Another piece of puzzle is reselect which allows us to keep the state as small as possible. And also greatly increases the decoupling factor.

It's still not perfect but it's a significant progress from what was available when I first came across this thread. Sample implementation can be found here.

I too have almost all isomorphic working, except need a way to accomplish server side rendering when data fetches are at component level. Without adding to the philosophical argument right now, for a long time I have been successfully using vanilla react (plus homegrown routing) with components fetching their own data in componentDidMount. I really dislike the idea of maintaining a redundant structure to define my component and data dependencies - that is already defined in my component tree, and here I just somehow need perhaps multiple render passes that incorporate data as it is fetched asynchronously, until the full component tree has been resolved.

Right now, I just wanted to second the growing importance of this for isomophic react, imo. I will try to work out a solution in the meantime. Thanks.

@decodeman in case you're interested, for Relate, I've done a minimal react traverser to get data dependencies from the components https://github.com/relax/relate/blob/master/lib/server/get-data-dependencies.js. This way I can get all the data dependencies -> fetch the data -> react render to string.

@decodeman, FWIW we have been using the double render approach (like what you allude to) successfully in a large production app. It is inspired by this redux-saga example, but the general approach should work well with any type of async loading. You just need to move loading to componentWillMount. To help keep it manageable, we also have higher order components that take care of common loading scenarios (e.g., check for prop x and load if nil.

I also think it would be very important to be able to load data within components and have some sort of lazy render method. Maybe to make both sides happy create a new method called asyncRenderToString and add a new "lifecycle" event called asyncOnLoad or something like that. This will only be called if you call a asyncRender method. In terms of code duplication between server and client side this can be fixed by developers of just moving common loading code into a separate method and call that method from asyncOnLoad and componentMount. Detecting if asyncOnLoad is done should probably use a returned Promise (if undefined is returned/method not defined it should directly call the applicable lifecycle events and then render) otherwise it waits until the promise resolves.

I think a solution like that would solve all the hacky ways we have to use at the moment for proper server side rendering. Including for example allow easy server side rendering of react applications with react router v4 (which not longer uses a centralized route config which is right now the only way to get isomorphic applications working)

This has been solved its called stream check out react stream.

On Thursday, November 3, 2016, Florian Krauthan [email protected]
wrote:

I also think it would be very important to be able to load data within
components and have some sort of lazy render method. Maybe to make both
sides happy create a new method called asyncRenderToString and add a new
"lifecycle" event called asyncOnLoad or something like that. This will
only be called if you call a asyncRender method. In terms of code
duplication between server and client side this can be fixed by developers
of just moving common loading code into a separate method and call that
method from asyncOnLoad and componentMount. Detecting if asyncOnLoad is
done should probably use a returned Promise (if undefined is
returned/method not defined it should directly call the applicable
lifecycle events and then render) otherwise it waits until the promise
resolves.

I think a solution like that would solve all the hacky ways we have to use
at the moment for proper server side rendering. Including for example allow
easy server side rendering of react applications with react router v4
(which not longer uses a centralized route config which is right now the
only way to get isomorphic applications working)


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react/issues/1739#issuecomment-258198533,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATnWLUIEJw4m1Y3A4oGDOBzP6_ajDcqIks5q6g4_gaJpZM4CHAWq
.

@yamat124 if I search for react stream I only find this project: https://github.com/aickin/react-dom-stream

At least based on the documentation there is no way to have a lifecycle event for preloading data which delays the next render call for subchilds until the Promise is resolved. Or are you talking about something else?

Again that are all very hacky ways. It requires routing to be independent of the component tree. And the "Main" component the route includes has to know all the data that needs to be loaded (Works 99% of the time but not always). Both would be obsolete if react has a delayed component render.

I agree, this is probably the thing i hate the most right now about react. Hate when people try to defend the framework from not having this feature by saying that it can be done manually, of course it can, like everything related to software development, but that doesn't mean that it should. The fact that there are tons of modules out there taking care if this precise thing should make a point by itself that it is something that should be solved from within the framework itself.

Next.js has an async getInitialProps to do server-side rendering, unfortunately just still need to call child's getInitialProps from the parents all the way back to the root. The Apollo GraphQL client also allows to traverse all the tree to gather the data requirements server-side then sending everything back. Example of Next + Apollo: https://github.com/sedubois/realate.

It would be great to have async React component lifecycle methods to combine these things together.

Just learned about SSR this week, hope what I write makes sense 😄

/cc @nkzawa @stubailo

BTW componentWill/DidMount are already async, does that help?

https://twitter.com/Vjeux/status/772202716479139840

@sedubois does React wait for the promise to resolve before rendering? Otherwise, doesn't really help!

@olalonde it seems so: https://github.com/sedubois/react-async-poc/blob/1d41b6f77e789c4e0e9623ba1c54f5ed8d6b9912/src/App.js

const getMessage = async () => new Promise((resolve) => {
  setTimeout(() => {
    resolve('Got async message!');
  }, 3000);
});
class App extends Component {
  state = {
    message: 'Loading...',
  };
  async componentWillMount() {
    this.setState({ message: await getMessage() });
  }
  render() {
    return (... {this.state.message} ...);
  }
}
loading got

@sedubois Note that, in your example, componentWillMount

  async componentWillMount() {
    this.setState({ message: await getMessage() });
  }

returns undefined and a promise, but the screenshots show that React doesn't wait (it couldn't) for the promise, because it renders the Loading... text.

Edit: Corrected.

@sedubois @polytypic It'll also cause all errors thrown within the function to be silently ignored, since the Promise isn't handled at all.

@polytypic @dantman I'm not quite sure what is meant by "the promise isn't handled at all". It's awaited by the await operator. You need to try-catch the error, I updated the example (using loading/error signature similar to what Apollo does).

    try {
      this.setState({ message: await getMessage() });
    } catch(error) {
      this.setState({ error });
    }

And render:

{error ? error : loading ? 'Loading...' : message}
screen shot 2016-11-07 at 13 25 46

@sedubois When you async a function it implicitly returns a promise, any throw in the function implicitly turns into a rejection of that promise instead of a throw up the stack. This means that componentWillMount is now returning a promise to its caller.

React does not do anything with the return value so your function is now returning a Promise expecting that someone is doing to do something with it, but it's just being tossed out instead.

Because it isn't handled, that means any rejection of that promise will not be caught by any code in React and any unhandled error will not show up in your console.

And even doing a try..catch won't perfectly protect you from this. If setState throws an error from your catch or you make a typo in the catch, that error will silently disappear and you won't be aware that something is broken.

@sedubois Actually, an async method does always seem to return a promise in JavaScript (well, future JavaScript). I was confused thinking about issues with async-await in C#. _Apologies for the noise!_

Nevertheless, the screenshots clearly show that React does not wait for the promise to be resolved. It calls render immediately after calling componentWillMount and renders the Loading... text. Then it calls render again after the call to setState. If React did wait for the promise to resolve it wouldn't render the Loading... text at all. Instead, it would wait until the promise resolves and would only then call render, which is the kind of behaviour this issue is all about: to be able to perform async IO during server side rendering.

@dantman @polytypic thanks 👍 Yes, for sure changes are needed inside React to wait for the response and handle errors properly. Maybe adding some await here and there in its code could do it 😄

Personally I'm using Web Workers to store application state and emit props on change (as I completely detached data storage and fetching from React components, and treat React just as renderer, to preserve the unidirectional flow principle), so it just waits until a message with the expected requirements (such as a specific property being true) to render.

That way, even if the first message(s) are intermediary "loading" states, they're not used for the static server-side renders, without the need for async component methods.

@sedubois It would have to be a different stack of methods; or a breaking change. React's current render methods are sync, so we'd need a different server render method that returns a promise.

@dantman I don't want to give any opinion here as these waters are too deep for me (my initial aim was just to point out Vjeux's async componentWillMount hack...), but hmm, can't React look at the type of object returned by the lifecycle methods and if it's a promise, handle it async and otherwise handle it sync (like currently, i.e in a backwards-compatible manner)?

I like what @fkrauthan proposed. A lifecycle method load which can return a promise or undefined and an additional async renderToStringAsync function. But load should always be called, on the client and on the server. If we use render or renderToString the returned promise is ignored to match the behavior we have today. If we use renderToStringAsync and load returns a promise, the promise has to be resolved before rendering.

Why not do like Next.js, add a React async getInitialProps lifecycle function which gets called before the constructor? If there is no such method, call the constructor directly.

const props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {});
...
const app = createElement(App, {
  Component,
  props,
  ...
});

It looks like Next.js manages to do the job, except that its getInitialProps is not hooked into the React component lifecycle so it can only be called on the top-level component. So the ideas are there and could just be joined together?

@sedubois I don't think getInitialProps is the correct place. First of all people that are using ES6 they don't have/use that method. Second of all you don't wanna work on the initalProps (that are just the defaults) you wanna work ontop of the merge of initalProps + passed in props. Therefor my suggestion of a new lifecycle event that gets dispatched before componentWillMount.

I think @Lenne231 idea could cause some problems as people might relay in there other lifecycle events for that promise to be already resolved. Having now two different behaviours of the same lifecycle event makes it a bit tricky.

Therefor there should be on the server and on the client one sync render method that not calls that new lifecycle at all. And a async version that calls that lifecycle and always waits until promise gets resolved before proceeding. That would in my opinion give you the greatest flexibility as you now can decide if you need that lifecycle on your client render too or just for your server render.

people that are using ES6 they don't have/use that method

@fkrauthan maybe you refer to getInitialState? Here I was talking of a new one, getInitialProps (the name used in Next.js).

As for your second point, yes it might be better to have the new lifecycle method before componentWillMount rather than before constructor. I guess it is not that way in Next because they do not have the luxury to tweak the React lifecycle as mentioned earlier. Hence why it would be great to bring those ideas within React.

@sedubois Even that one. I use for example the es7 feature and define static props = {}; In my class body. That makes the code way nicer to read in my opinion and I am sure more and more people are going to switch to that as soon as es7 is official released.

Note: class properties are not an "ES7" feature because ES7 has already been finalized and the only new language feature there is exponentiation operator. What you're referring to is stage 2 class properties proposal. It's not part of the language yet and might change or get dropped.

I don't see the need for async functions in react for fetching data, instead I'd be happy with a virtual renderer that would renderToString on demand. So you could set actions and the virtual tree would update accordingly before rendering to string. This I think would be ideal to achieve a good SSR in react. Leaves to the developer how and where to fetch the data.

I've mentioned before but a good api would be something like the following (with a little update with what I've suggested before):

const virtualTree = ReactDOM.renderVirtual(rootEle);

// get the bundled query from redux store for example
const bundle = store.getState().bundle;

// Fetch the data according to the bundle
const data = await fetchDataSomehow(bundle);

// hydrate store (this will set updates on the virtual tree)
store.dispatch({type: 'hydrate', data});

// final result
const domString = virtualTree.renderToString();

This would avoid the problem some GraphQL client such as Apollo are having that enforces them to make a double renderToString. Being the first to fetch data dependencies, and the second render with the data populated. I think this is quite a waste of processing since renderToString is quite expensive.

@bruno12mota I see your point but again just the amount of libraries that try to simulate that (and with your solution there still will be thousands of libraries) is to me a sign that maybe that should be a core feature rather then something you have to build on top. Your solution would still require way more render calls (virtual but still render calls) to get the output.

@fkrauthan yes but virtual renders are far more performant than having to make two renders to string, which is the main issue here in my opinion (performance in SSR) it's the weak part of React. There has been a few experiments to improve react's renderToString but there's no real advance on this matter by the react team (not criticizing here, they do an amazing job).

I agree with @bruno12mota, having also deliberated on this issue for a while now, that is the simplest approach. It leaves the freedom to the developer to determine when their render should "flush".

It makes everything a lot more complicated.

1.) From a code point of view (I looked thru the code and making the render async should be way easier then creating a renderer that just uses VDom and then can be dumped at one point)
2.) Now you have to reconsider unmount events too. And it makes the custom code way more complicated then needed. E.g. loading data might result in rendering a new component that also needs to load data. Now all the sudden the lib needs to figure out which component at which position already loaded data and which component contains new data loading and things.

I'm with @bruno12mota. A VDom is arguably a more "low level" solution but would probably be easier for React developers to implement, wouldn't have backward compatibility issues and could allow the community to experiment with different higher level solutions.

For example, one higher level solution could be a "higher level component" that wraps async componentWillMount methods, waits for all pending promises and fire VDom.renderToString() when everything is resolved. I'm using this sort of strategy for SSR in my app though I unfortunately do a lot of over fetching right now because there is no VDom.

I think the best way would be to not change any functions we currently have. Which means not making getInitialState, componentWillMount, or renderToString behave differently.

Instead, we should add new functions to solve the problem discussed here. Just like there are functions that only get called on the client, there could be functions that only get called on the server.

I think we could add a function "renderToStringAsync" to react-dom/server. The difference to the normal renderToString would be, that it returns a Promise.

On the implementation side, the only difference would be that the async version would, whenever it creates a Component instance, call & await "initialize()" on it first, before it calls render(). If the component does not have an "initialize" method, it could call render() immediately.

So if we have the following example App structure:

    ComponentB
    ComponentC
        ComponentD
        ComponentE

the process would be:

1) instanciate componentA
2) await componentA.initialize();
3) componentA.render()
4) do in parallel(
    instanciate componentB, await componentB.initialize(), componentB.render()
    instanciate componentC, await componentC.initialize(), componentC.render(), do in parallel(
        instanciate componentD, await componentD.initialize(), componentD.render()
        instanciate componentE, await componentE.initialize(), componentE.render()
    )
)
5) render to string

So, basically, we just need a new function "renderToStringAsync" which makes use of a new, optional function "initialize". It would not be that hard.

@VanCoding has the same idea I have been thinking about for a while. I was wondering if initialize could also be called automatically in componentDidMount on the client?

So on the server it would be:

initialize()
render()

And on the client it would be:

render() // without data (unless available synchronously)
componentDidMount()
initialize()
render() // with data

I have a working implementation of react server rendering with react-router v4, and react-apollo with GraphQL.

it was inspired by server-side-rendering-code-splitting-and-hot-reloading-with-react-router.

Basically server rendering use synchronized component, client rendering use asynchronized component so that webpack async loading and executing module javascript.

By the way the server rendering is implemented with Nashorn Script Engine (JVM).

Client rendering code
https://github.com/shendepu/react-ssr-starter-kit/blob/apollo/src/main.js#L63-L82

Server rendering code
https://github.com/shendepu/react-ssr-starter-kit/blob/apollo/src/main.js#L128-L155

There is one important place to distinguish synchronized or asynchronized component in route.
Synchroized comonent in Route
https://github.com/shendepu/react-ssr-starter-kit/blob/apollo/src/routes/Counter/Route.js#L10

Asynchronized component in RouteAsync
https://github.com/shendepu/react-ssr-starter-kit/blob/apollo/src/routes/Counter/RouteAsync.js#L7-L23

NOTED: the file name MUST be Route.js or RouteAsync.js. The code should always import RouteAsync.js. Webpack will replace it with Route.js if it is built for server rendering.
https://github.com/shendepu/react-ssr-starter-kit/blob/apollo/build/webpack.config.js#L72-L80

So there will be two version of build dist and dist_ssr, dist is for client while dist_ssr is for server which only has two chunks: vendor and app. The store state is exported and embedded in <script> of index.html as __INITIAL_STATE__. The reason to have two versions of build is ReactDomServer.renderToString() does not support async component yet.

The only issue with two-versions-build approach is that there is warning in dev mode:
React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:

But since only difference between client and server version is Route.js and RouteAsync.js, so the warning can be ignored, warning does not show in production mode.

For async data fetching before component rendering at server side:

  • Rest API: Added static loadData in the component use
const { matchedRoutes, params } = matchRoutesToLocation(rootRoute.routes, 
                                                        location, [], {}, rootRoute.pattern)
matchedRoutes.filter(route => route.component.loadData).map(route =>
              route.component.loadData(store, params))

to probe and execute loadData. matchedRoutes is an array of matched routes which parent is from index 0. loadData can be executed in sequence or in parallel.

  • GraphQL Query: simply use getDataFromTree from react-apollo/server to execute all GraphQL query.

BTW: using Nashorn Script Engine has one performance optimization opportunity: Since vendor contains library code and polyfills which is executed once and reused, so for later requests, only app chunk is executed. Since libraries are moved into vendor chunk, app contains only javascript code in src which is small, so it is performance boost comparing to evaluating vendor chunk every time. (all javascript is compiled once and cached, executed for every request.)

I lied that app chunk only contains src code. it also contains babel-runtime and duplicated core-js/library referenced by babel-runtime. babel-runtime can't be moved into vendor chunk due to it has no index.js or main entry so that webpack could not recognize it as a module. but the code size is small.

Let's elaborate further @VanCoding's example: https://github.com/facebook/react/issues/1739#issuecomment-261577586

Maybe initialize isn't a good name - the name should kind-of make it clear that it's intended to be used only on the server, or in an environment where the rendering is delayed until this function returns - aka not in the client. Ideas: getStaticProps, getServerProps, getInitialProps, getAsyncProps...

Also it would be good to hear from the core team whether there are technical or otherwise impediments to developing such a renderToStringAsync method.

@nmaro Well, I think the function shouldn't return anything, so I'd prefer a name that does not start with "get", but apart from this, I still think this would be the best way. I don't mind the how it's called in the end.

Besides, I've done a proof of concept for this, in about 40 lines of code. It's not intended for production use, but my tests with various components were successful.

So, if the react team still does not want this to happen, it would not be that hard to do it in a 3rd party library.

Alternatively we could add an option to renderToString, as in
renderToString(Component, {async: true})

@nmaro That would make the return type of the function dependent of the provided options, which I don't consider good practice. I think a function should always return a result of the same type.

@VanCoding do you have an example of how to use your code as a third-party lib?

@VanCoding cool! But honestly, I think it's going to be hard to integrate that into react's internal rendering algorithm. Check out https://github.com/facebook/react/blob/master/src/renderers/dom/stack/server/ReactServerRendering.js and get lost in react's internals... IMO we really need an opinion from someone from the core.

@sedubois you can use the function like you would use the normal renderToString function. But it returns a Promise that resolves to a string, instead of returning a string directly.

So using it would look like:

var react = require("react");
var renderAsync = require("react-render-async");
var MyComponent = require("./MyComponent");

renderAsync(react.createElement(MyComponent,{some:"props"}).then(function(html){
    console.log(html);
});

In theory, it should be able to render any existing react component the same way that the normal renderToString does. The only difference is that async components are supported as well.

@nmaro You're right. That would be helpful.

What is the status on this?

@firasdib We're still waiting for some react devs to comment, I think.

+1

Google indexing problems demand SSR and all the baggage described below is for us to deal with and thus this issue is very important for React to succeed as a general library.

I think the whole async rendering is not necessary if JavaScript provided a proper way of waiting on a promise. Then we could pass a parameter indicating weather or not we want data loading to be synchronous (for SSR) or async (for real web browser). The data loading logic could start a promise in any React component's constructor and wait could be done in componentWillMount.

However, as I understand React devs have shown doubt in usefulness of componentWillMount and recommended to make constructor do all the work. Either way will work.

Some people have argued that making components pure views addresses the issue. They are partially correct. Unfortunately, this does not work in the most generic case where we don't know what data to load until render tree is done.

The core of the issue is that render function can have logic to select what components to add to the DOMTree. That's what makes React so powerful and so badly suited to server side rendering.

IMO the true solution is to be able to register all issued data loading promises with react. Once all data loading promises complete react calls us back with render result. This has a number of implications:

  • the DOMtree will get rendered several times. It is like a live system that "settles" from unstable data loading state into a stable "loaded" state.
  • there is a risk that the system will not arive to a stable "loaded" state in a buggy system. Time out has to be introduced to deal with it.

The result is a much more "computing intense" use of the library on the server side with a process that's not fast.

Thus, I am still thinking of a workaround that will compromise the generic case in favor of getting things done :)

In a mean time we have to solve SSR in async data loading environment.

  1. Data loading calls have to be derived from request URL (react-router is an example). Collect all data loading promises into a single list of promises.
  2. Use Promise.all(), which is in itself is a promise. When this promise completes pass loaded data to server rendering function.

This model is not tied to a particular design architecture. It seems that flux/redux might benefit slightly, but I am not sure as I have abandoned redux model in my application.

The problem in this model is item #1 above. A simple application knows all the data loading calls. In a complex application with independent "modules" this model requires some kind of replication of original React component tree and even render logic.

I don't see how SSR can be made to work on the complex project without repeating the logic already written in render() function. Flux might be a solution, but I not experienced in it to be sure.

Item #1 implementation is vague. In react-router example we have to as router to returns to us top level components that belong to that route. I think we can instantiate these components:

app.use(function(req, res, next) {
    match({ routes, location: req.url }, (error, redirectLocation, renderProps: any) => {
    if (error) {
        res.status(500).send(error.message)
    } else if (redirectLocation) {
        res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
        // You can also check renderProps.components or renderProps.routes for
        // your "not found" component or route respectively, and send a 404 as
        // below, if you're using a catch-all route.
        console.log("renderProps", renderProps)
        for (let eachComp of renderProps.components) {
            // create an instance of component
            // ask component to load its data
            // store data loading promise in a collection
            console.log("eachComp: ", eachComp)
        }
        res.status(200).send(renderToString(<RouterContext {...renderProps} />))
        } else {
        res.status(404).send('Not found')
        }
    })
});

So, top level components are no longer "pure" components. These components now play a role of top level controller, due to ability to trigger data loading. Flux model does not make it any better. It simply moves route to data loading function association into a different module.

Unfortunately, continuing with data loading this way to the children of top controllers results in a duplication of object graph created for react rendering purpose. To keep things simple (if possible) we have to put all data loading into top controller level.

That's what I see.

If I realized these SSR implications, I would've thought twice about usefulness of React for google indexable applications. Perhaps flux is a solution, but flux makes application a whole level more complicated than a simple React application. I've been there. Instead of simple data loading function I have to chase my logic across multiple files. At theoretical level it looked really really good until I had a project running. New people had hard time to get started. No such problem after pulling redux out of code base. I thought it was the answer to all UI design complexities :)

From this week's React Conf, after React Fiber (React 16) is out, they are planning to work on the following (supposedly for React 17):

screen shot 2017-03-16 at 15 55 51

Means async React lifecycle methods could be coming?

Well, isn't the fiber stuff mostly about faster/smoother re-rendering? On the server, we render only once, so I'm not sure if those changes will have any effect on serverside rendering.

@VanCoding updated my above message which was a bit unclear. I meant their plans for after fiber is out.

For folks landing here like me, I ended up creating a custom implementation using react that might help.

https://github.com/siddharthkp/reaqt

the key is asyncComponentWillMount which runs only on the server. it is available only to entry point components, not all components to avoid the issues mentioned here.

@siddharthkp I don't really see what your component tries to solve? If it only supports asyncComponentWillMount for the Top Level Application React component why should I use your library at all? I could just resolve that promise outside and then call render? Or did I miss something?

@fkrauthan

I could just resolve that promise outside and then call render?

You're right, that's exactly what it does.

The appeal is that you get async ssr (+ code splitting + hmr) with one command. I saw a lot of folks not implementing ssr because it's not super easy, and that was the motivation.

it only supports asyncComponentWillMount for the Top Level Application React component

  1. Does not have to one application component. You can fetch data for each page/screen/entry point. (promoting multiple entry points here)

  2. The pattern is intentional, if every component in the tree wants it's own data, we might end up encouraging a bad pattern for performance. Fetching data at the top level component and passing it to children as props keeps it in check.

@siddharthkp how does your repo improve over Next.js (which was also presented at React Conf BTW)?

https://github.com/zeit/next.js

Anyway discussion about third-party libraries is IMHO off-topic, what we're interested in is support within React itself.

discussion about third-party libraries is IMHO off-topic, what we're interested in is support within React itself.

I completely agree. Can discuss specific questions in reaqt issues

A usecase I have for this is with using react-native and react-native-vector-icons. I want the prop of a component to be determined by the data received from a promise

const AsyncUser = props => fetchUser()
  .then(data => (
     <User {...data} />
   ))

If supported I think this would make lots of complex code easier to understand and possibly open up new async patterns.

we have the same issue, i want to do the ssr, not only search the predict props but also the content fetched by action in componentWillMount, how can i wait the props is prepared, then render the props to string.

If anyone finds this useful, I've written a library called react-frontload that lets you bind a promise-returning function to a component to run when the component renders, on both server and client renders.

The function runs 'synchronously' on server render (well not really ;-) but the final component render is blocked until it has resolved), and asynchronously as normal on client render, and does not run again on the client if the page was just server-rendered. There are also more options you can specify for finer-grain control of when it runs, on a per-component basis.

It's really useful for data loading - pretty much the use case I wrote it to solve. Try it out! 😄

https://github.com/davnicwil/react-frontload

<AsyncComponent 
  delayRendering={LoadingComponent}
> 
   {/*return a promise that returns a component here*/}
</AsyncComponent>

Think of all the conditional rendering you wouldn't have to do with the above approach because you know you have your data

Joining in on this one. I think it's still an essential feature that React lacks. Also agree that even if third party libs may cover this subject, this should come directly from within.

I came up with an implementation https://github.com/timurtu/react-render-async

Very nice async component interface, @timurtu.

...Hey everyone, just wanted to chime in here as I have various things that relate very directly to this thread, and I've been tracking this thread for a long time:

  • For one, considering SSR, I think route-level data-fetching makes the most sense--here's why:
    Redux-First Router data-fetching: solving the 80% use case for async Middleware
  • server rendering with Redux is now stupid simple, here's a step by step guide with Redux-First Router of how to do it like you've never seen it done before: Server-Render like a Pro /w Redux-First Router in 10 steps
  • lastly, to do code-splitting right, you also have to do both (i.e. both SSR + Splitting). It turns out simultaneously doing both has been a major pain point, successfully achieved by few, and never until now having a general package to help the community. React Universal Component + babel-plugin-universal-import + webpack-flush-chunks (and extract-css-chunks-webpack-plugin) are a family of packages that really solve this matter. And for the first time. Basically, it allows you to render components synchronously on the server, but more importantly transports the exact chunks rendered to the client for an initial synchronous render on the client as well. You even get css chunk stylesheets via the webpack plugin. This is different than what @timurtu shared and many such components, which require loading main.js, parsing, evaluating, rendering and then finally a few seconds later requesting the dynamic imports. These are solutions to solve flash of unstyled content (FOUC), but not to embed in your page the exact chunks rendered on the server. Universal--the name of my family of packages--allows you to do so with far faster time till interactive (TTI) in a synchronous way that operates like traditional webapps. You can learn more about it in this article: React Universal Component 2.0 & babel-plugin-universal-import

I know I didn't address route level vs component level pros/cons, but the first link focuses primarily on that. Basically it boils down to component level being bad for SSR if you have nested components whose data must be fetched in sequence (rather than parallel). And if you correctly only have one fetch to make per route, well, you're better off formalizing the contract by attaching your data dependencies to a route entity, instead of doing it in componentDidMount. Many others above came to this same conclusion. Redux-First Router formalizes this very nicely along the lines of the sort of "contracts" that make Redux so pleasant to work with.

Redux-First Router makes a lot of old paradigms new again, but surprisingly fits right in as a missing piece to the Redux ecosystem. If you've ever wanted a router native to Redux's workflow, give Redux-First Router a try. It's relatively new, and I'm a newcomer to open source, but it's something I've worked on for basically a year and it's gotten a lot of traction in the 2 months it's been out. People are lovin it. I really hope you check it out and give it a shot :).

Here's also its launch article which explains how it's a far better solution for Redux than React Router, and how it gets the vision right in a way that the also excellent Redux-Little Router missed unfortunately:
Pre Release: Redux-First Router — A Step Beyond Redux-Little-Router

The primary difference between RLR and RFR is that RFR dispatches a different action type per route (i.e. URL change), instead of always just LOCATION_CHANGED. This lets you switch over URL changes as unique types in your reducers, just like any other actions. It may seem small, but it makes a huge difference. Because of that, it doesn't require <Route /> components, something that are unnecessary in Redux land. There's also a huge laundry list of features Redux-First Router supports from data-fetching in route thunks to React Native, React Navigation, code splitting, prefetching, and more.

Would love to hear people's thoughts.

@faceyspacey thank you, I think it addresses the problem I was having which is when you want to set props based on async data for example, react-native-vector-icons can return an icon as a promise. It's definitely a different way of looking at things but it reduces componentWillMount or redux X_GET_START, X_GET_END, and X_GET_ERROR action boilerplate that tie async components to state, when you really only want to make that request one time to render the component. If you're doing things like polling data then being stateful and using redux probably makes more sense

@faceyspacey I see what you're saying about route level, but wouldn't it be better to have smaller components that only rely on fetching the data they need while rendering everything else around them synchronously?

Better? Where? On React Native? In large organizations like Facebook on their React Native apps?

Maybe on React Native. When there is SSR in my view there is no debate. What you want to do is simply not possible without multiple fetches per request, unless, again, u limit it to one component that can do the fetch. At which point, you're better off formalizing the contract with route entities.

As for React Native and SPAs, sure. But testing components that have data deps built in is a pain. Apollo has some stuff here but last I checked they had a long todo list to get data-paired component testing really right, i.e. seamless. I prefer a setup where you have one store that's easy to setup and mock. You can reuse how u do that in all your tests. Then from there testing components is simple synchronous rendering with snapshot taking. Once you add data deps in components, testing React becomes less intuitive. But people do it and automate it. There's less of a standard and it's now closer to custom ad-hoc code. It's more to productive to have a store that can be populated asynchronously in a very obvious way, rather than have potentially different strategies for every async component that needs to be populated.

I'm not against component level if there is no SSR and u have your testing strategy seamless and out of the way. If u are mega corp it makes sense because then every developer doesn't need to touch the top route level and potentially break it for others. That's why FB pioneered this route with Relay and GraphQL. The fact of the matter is only like 100 companies in the world are truly in this boat. So I view colocation as more hype than reality for most people/apps/companies. Once you get the hang of the route level thing and have a package that does it really well like Redux-First Router, then you have a far less tangled easier to develop approach for teams whose members are allowed to touch route level. Just check out Demo on the homepage of codesandbox:

https://www.codesandbox.io

Basically once you see how it's done I'd love to hear your opinion. Keep in mind this is an SPA. So u will have to review the demo repo or boilerplate for an SSR example. But this is a good start.

I think the easiest way will be supporting async render method (render returns a promise). It will allow root component wait children components rendering and of course result of render will be a promise. I implemented something like this in preact here https://github.com/3axap4eHko/preact-async-example

@faceyspacey Thank you for the detailed answer above. I really like the idea of Redux-First Router, it definitely solves all of my problems, and makes things much more transparent and clean than what we had before.

Big thanks!

@raRaRa glad you like it! ...one of the biggest challenges is there hasn't been a good abstraction for route level data-fetching until now. React React v3 had callbacks, and the v4 has an excellent pattern (particularly with the react-router-config package), but it's non-obvious and not first-class in the v4. It's an after-thought. More importantly however, it doesn't live in Redux. So it's only really now for the first time that redux users have a complete "route level" abstraction.

I think now with RFR, we're gonna see a re-thinking of the importance of "route level" vs "component level." Things like Relay and Apollo have created a lot of hype around pairing data dependencies to components, but if you aren't using those 2, you're likely going to end up in a world of hurt at some point by doing things in lifecycle handlers.

That said eventually RFR will have a route level integration with Apollo. There's just very little benefits for doing things at the component level, minus the aforementioned rare exceptions. At least 80% of the time (and perhaps 100% in your app), you can determine all the data you need based on the route. If it's not possible, it's likely because you're deriving data in your "view layer" that very well could be re-thought to all be interpreted by the URL. So even with tools like Apollo you begin to engage in problematic anti-patterns that will likely eventually cause you pain by letting "state" live nowhere else but the view layer. I.e. the state necessary to perform those data-fetchings. You often have to refine the exact parameters used to fetch your data. So you take state and props and transform the 2 to get the params just prior to fetching the data. That's stuff that now lives in the view layer and subject to its re-rendering mechanisms (i.e. when lifecycle handlers are called). Every app at one point or another ends up with the data not fetched when it should be or fetched in response to unrelated props received/changed. And in all apps, you have to write extra code to guard against unrelated props that have changed. I.e. props that don't affect the params used to fetch data.

As for React Native + Apollo, there the problem is less because you don't have SSR and therefore potential for sequential data-fetchings happening on the server. However, do you really need component level data-fetching when screens are so small. You generally know what each "scene" needs in terms of its data. It's not like a desktop web panel dashboard with a million graphs, multiple tables, etc. That one use case is perhaps the biggest primary place where component level starts to make sense. But even there you can specify all your requirements for all those widgets in one place and fetch them via Apollo. I haven't given it enough thought yet, but the basic idea is to attach your GraphQL data-requirements to a route, and then in your components connect to the data just like any other Redux data. So more specifically, the idea is to eliminate having both react-redux's connect and Apollo's equivalent. I just want one, and we want it to be flatter. Using Apollo requires destructuring more deeply nested data to gain access to what you truly want in your components. The vision is one way that looks just like regular Redux, plus graphql specifications at the route level.

It's a bit premature to be talkin about it, as I have barely looked into it, but if route level is the correct approach for your app, Apollo + GraphQL shouldn't be an exception.

Lastly, testing is so just so much easier if all your data-dependencies and async work are separated from components. Separation of concerns is a major productivity booster when you can test your components without having to worry about data-fetching. Of course in your tests you must populate your store by doing those async fetchings ahead of time, but with them separated from your components, you can easily formalize such work under some setup helper functions all your tests use to pre-populate the store before testing how components render :)

@faceyspacey I completely agree. But I must admit that I haven't tried out Apollo nor GraphQL, I will definitely check them out and see how they fit my use cases.

I'm very used to writing web applications using the MVC pattern, where I basically pull all the data and dependencies on the controller. Then I inject the data to the views or the business logic. Like you said, that makes testing much easier since the view isn't coupled with the data fetching.

I've seen MVC applications where the View part is fetching data and doing business logic, and it's terrible. Both I have no clue what data will be fetched because it's hidden in some view/component and testing becomes harder/impossible.

To me, Redux-First Router is very much like the Controller part in MVC, plus the routes. Which makes so much sense :)

Thank you.

At the end of the day, our new stack is this:

M: Redux
V: React
C: Redux-First Router (soon to be renamed to "Rudy")

When React came out (and particularly Redux), we all seemed to want to throw out the ancient wisdom of MVC, as if somehow it meant we could completely clear ourselves of the pains in developing previous applications. But I think ultimately it's nothing more than simply not having the tools built yet to support it. At the end of the day we still benefit greatly from MVC, even in reactive client-first applications.

It may work a bit differently in the new client-first stack vs. traditional server-side MVCs, but basically it's the same 3 separation of concerns.

As far as what the difference in interaction/behavior between the 3 is, it's basically that in the past the controller would get models in an initial phase and then render the views with them; and now it's the controller (RFR) immediately rendering a view (chosen via a "UI model," i.e. Redux state), and then re-rendering the view a second time once the controller finds domain models (also stored in Redux state).

Hello guys, watch this link. here is data server side rendering example https://github.com/bananaoomarang/isomorphic-redux

@harut55555 idk it may just be me but this seems like a lot of code to do a get request and a post request

Any changes? Released 16 react and most of solutions do not work

I think the current approach is use redux with tooling like redux observable or redux thunk

My case of use

<App>
    <Page>
        <AsyncModule hre="different.com/Button.react.js" /> downloaded from external url on server or client
    </Page>
</App>

The problem is that I do not know before rendering the App what kind of components I will have

Why not download data/content instead of a component just curious?

When? I have dynamic pages and the component may or may not be

Sounds like you want conditional rendering https://reactjs.org/docs/conditional-rendering.html

I think that it's routing problem, react should only render page, not manage and request render data

Using @graphql from Apollo makes data loading super simple, and the React-Router v4 component-based API makes for simple composable routing. Both are orthogonal to application state in Redux.

In order to do single-pass streaming rendering which waits for data fetches, it should be possible for render() to return a promise (on the client you just do as now, only on the server you return a promise).

Then @graphql can simply return a promise for the render() after data being loaded; all the rest is just plain React.

A few months ago I gave a talk at JSConf Iceland that describes the upcoming async rendering features in React (see the second part): https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html. This is about client-side data fetching.

Now @acdlite gave a talk about how the same concepts can apply to enable asynchronously waiting for data on the server in React components, and progressively flushing down the markup as it’s ready: https://www.youtube.com/watch?v=z-6JC0_cOns

Hope you’ll enjoy watching these talks! I think that in a year or so we might be able to close out this issue and have an official strategy for this.

I remember ring. Us getting married planning a future together. Please end this now and come see me. Time worked always love

It's possible to use ReactDOMServer.renderToStaticMarkup to walk the tree, place a bookmark where it reaches asynchronous dependencies (typically loading data from an API), and continue walking the tree as those dependencies are resolved, until the whole tree is resolved, and then do a final ReactDOMServer.renderToString to actually render to HTML, which will be synchronous because all the dependencies are now resolved.

I've taken this approach in react-baconjs: render-to-html.js. It was inspired by a comment @gaearon made in another issue recommending such an approach.

@steve-taylor yeah, this works. It's also the workaround I use in react-frontload which is a more general purpose solution to this which will work in any React app.

As you say essentially it's just faking asynchronous rendering by running synchronous rendering logic twice and waiting for all the data-loading promises you hit on the first render to resolve before you run the second.

It works well enough despite obviously being a bit wasteful (output of first render is more than just promises, it's also the actual HTML which is just thrown away). Will be amazing when true async server rendering makes it into React.

@davnicwil nice work! I have thought about generalising the specific async SSR solution. Does react-frontload handle unlimited async depth? Asking because you said “twice”.

@steve-taylor cheers! Yep, if by depth you mean depth of component in the tree, it's unlimited. It lets you declare a data loading function on the Component itself (with a Higher Order Component) and then when that's encountered on the first render it's run and the promise is collected.

What won't work is when there are further child components that also load data asynchronously that would then be rendered dynamically depending on the result, if that makes sense. It just means the app has to be structured so that there's not this kind of nesting, which I've found in practice is not really a massive limitation. In fact in many ways it's better UX-wise because of course nested async logic means serial requests, and longer wait times, whereas flattening means parallel requests.

That said the nesting problem (indeed maybe this whole async server rendering problem) may be solved with the Suspense stuff coming into React in the near future. 🤞

FYI we’ve started work on this.

https://reactjs.org/blog/2018/11/27/react-16-roadmap.html#suspense-for-server-rendering

Awesome @gaearon!

@davnicwil react-baconjs supports unlimited depth.

@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.

@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.

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.

Was this page helpful?
0 / 5 - 0 ratings