【问题标题】:How to render asynchronously initialized components on the server如何在服务器上渲染异步初始化的组件
【发布时间】:2013-12-28 14:01:48
【问题描述】:

我对 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 的全部意义)?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

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

    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 请求数量,因此值得考虑您的架构,以便您可以在服务器上收集您需要的所有数据。

    【讨论】:

    • 感谢您的回答。实际上,其中的“HTTP”部分不是我的主要问题,对于初始化组件所涉及的任何异步操作,问题都是相同的,例如数据库查询(在我当前的设置中,由于历史原因,数据库查询被委托给第二台服务器,该服务器实现了 HTTP REST api)。我的目标是以某种方式将组件标记为“仅部分初始化”,等到所有组件的初始化完成,递归(即引入的新组件也完全初始化),然后只调用renderComponentToString。
    • 我明白了。目前,renderComponentToString 总是同步运行,所以没有简单的方法来做你所要求的。
    • 很好的方式来做到这一点,而不必包含额外的外部库,如react-async。这对任何异步操作都非常有效——我的应用程序没有使用 AJAX,而是使用 PostMessage。这对我来说是一个优雅、简单的解决方案。谢谢!
    【解决方案2】:

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

    【讨论】:

    • react-async 被最新版本的 react 破坏了。你知道react-async 的其他替代方案吗?
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2017-08-19
      • 1970-01-01
      • 2016-07-23
      • 1970-01-01
      • 1970-01-01
      • 2016-11-15
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      相关资源
      最近更新 更多