19

我对 ReactJS 比较陌生,并且被易于实现服务器端渲染以减少“第一次发推文的时间”所吸引。我正在运行一个 Node-Express-React 堆栈,它使用 React 的 renderComponentToString 在服务器上预渲染标记。

当组件可以同步呈现时,它工作得很好,但是在实现 ajax 填充的组件时我正在苦苦挣扎(但这适用于组件初始化期间的任何异步操作,例如 websocket)。

以 React 网站为例: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));

它不会在服务器上工作,因为使用 renderComponentToString 时不会触发 componentDidMount。这个简单的情况可以通过在客户端和服务器上使用相同的 HTTP 请求包装器(而不是使用 jQuery 的 $.get),并通过在实例化组件之前预取数据并将其作为道具传递来解决。

然而,在一个实际的、复杂的应用程序中,异步依赖可能会变得非常复杂,并且预取并不真正适合构建 React 结构的后代方法。我如何在 React 中实现异步初始化模式,它可以在服务器上呈现而无需实际安装任何东西(即没有 DOM 模拟 la PhantomJS,这是使用 renderComponentToString 的全部意义)?

4

3 回答 3

4

我相信最实用的方法是为预加载的数据制作一个可选的道具,如下所示:

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));
    }
},

通过这样的设置,如果存在预加载的数据,则可以立即渲染组件;否则将在挂载时发送 AJAX 请求。

目前,服务器渲染始终是同步的,并且componentDidMount不会在服务器上调用,因为它通常涉及 DOM 操作。抱歉,我现在没有更好的解决方案,但总的来说,您希望最大限度地减少对服务器的 HTTP 请求数量,因此值得考虑您的架构,以便您可以在服务器上收集所需的所有数据。

于 2013-12-28T17:54:56.573 回答
3

你可以看看react-quickstart项目,它使用react-async并附带了一个服务器渲染示例。react-async提供了一个装饰renderComponentToString方法,该方法可以预取异步状态并将其呈现到初始标记中。但是,您需要将异步状态与“常规”状态分开指定。

于 2014-05-07T03:04:58.353 回答
0

您可以查看 react-nexus ( https://github.com/elierotenberg/react-nexus ),它可以帮助您提前声明所有异步依赖项。

但我意识到 react-nexus 是你自己解决这个问题的答案,所以你可能已经找到了!

于 2016-07-04T10:25:28.450 回答