I'm relatively new to ReactJS and have been seduced by the ease of implementing server-side rendering to reduce "time to first tweet". I'm running a Node-Express-React stack which pre-renders the markup on the server using React's renderComponentToString.

It works fine when the components can be rendered synchronously, however I'm struggling when it comes to implementing ajax-populated components (however this applies to any asynchronous operation during the initialization of the component, e.g. websocket).

Take the example from the React website: http://facebook.github.io/react/tips/initial-ajax.html

componentDidMount: function() {
 $.get(this.props.source, function(result) {
  var lastGist = result[0];
  this.setState({
    username: lastGist.user.login,
    lastGistUrl: lastGist.html_url
  });
}.bind(this));

It won't work on the server, since componentDidMount is never triggered when using renderComponentToString. This simple case can be worked around by using the same HTTP request wrapper on the client and on the server (instead of using jQuery's $.get), and by pre-fetching the data before instantiating the component and passing it as a prop.

However, in an actual, complex app, asynchronous dependencies can get very complicated and pre-fetching doesn't really fit the descendant approach of building React structures. How can I implement an asynchronous initialization pattern in React that can be rendered on the server without actually mounting anything (i.e. no DOM emulation a la PhantomJS, which is the whole point of using renderComponentToString) ?

没有正确的解决方案

其他提示

I believe the most practical way to do this is to make an optional prop for the preloaded data, like so:

getInitialState: function() {
    if (this.props.initialLastGist) {
        var lastGist = this.props.initialLastGist;
        return {
            username: lastGist.user.login,
            lastGistUrl: lastGist.html_url
        };
    } else {
        return {};
    }
},

componentDidMount: function() {
    if (!this.props.initialLastGist) {
        $.get(this.props.source, function(result) {
            var lastGist = result[0];
            this.setState({
                username: lastGist.user.login,
                lastGistUrl: lastGist.html_url
            });
        }.bind(this));
    }
},

With a setup like this, the component can be rendered immediately if the preloaded data is present; otherwise the AJAX request will be sent while mounting.

Currently, server rendering is always synchronous and componentDidMount isn't called on the server because it usually involves DOM manipulation. Sorry I don't have a better solution here right now, but in general you want to minimize the number of HTTP requests to the server so it's worth thinking through your architecture so that you can collect all the data you need on the server.

You could take a look at the react-quickstart project, which uses react-async and ships with a server-rendering example. react-async provides a decorated renderComponentToString method that pre-fetches asynchronous state and renders it into the initial markup. However, you will need to specify asynchronous state separately from 'regular' state.

you can check out react-nexus (https://github.com/elierotenberg/react-nexus) which helps you declare all your async dependencies ahead of time.

but I realize that react-nexus is your own answer to this problem so you probably already found it !

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top