【问题标题】:ReactJS server-side rendering vs client-side renderingReactJS 服务器端渲染与客户端渲染
【发布时间】:2015-02-02 02:46:53
【问题描述】:

我刚开始研究 ReactJS,发现它为您提供了两种渲染页面的方式:服务器端和客户端。但是,我不明白如何一起使用它。是两种不同的方式来构建应用程序,还是可以一起使用?

如果我们可以一起使用,该怎么做——我们是否需要在服务器端和客户端复制相同的元素?或者,我们可以只在服务器上构建应用程序的静态部分,在客户端构建动态部分,而不与已经预渲染的服务器端建立任何连接吗?

【问题讨论】:

  • 简短回答,否 - 您可以解耦、发送静态 html 并在客户端渲染中完全更改它。在我的回答中添加了详细信息。

标签: javascript node.js client-server reactjs


【解决方案1】:

是两种不同的方式来构建应用程序,还是可以一起使用?

它们可以一起使用。

如果我们可以一起使用,怎么做 - 我们是否需要复制 服务器端和客户端的元素相同吗?或者,我们可以 在服务器上构建我们应用程序的静态部分,以及 客户端的动态部分,与服务器没有任何连接 已经预渲染的那一面?

最好呈现相同的布局以避免重排和重绘操作,更少的闪烁/闪烁,您的页面会更流畅。但是,这不是限制。您可以很好地缓存 SSR html(Electrode 可以减少响应时间)/发送被 CSR(客户端渲染)覆盖的静态 html。

如果您刚开始使用 SSR,我建议您从简单开始,SSR 很快就会变得非常复杂。在服务器上构建 html 意味着失去对窗口、文档等对象的访问权限(您在客户端上有这些对象),失去合并异步操作的能力(开箱即用),以及通常需要进行大量代码编辑以使您的代码与 SSR 兼容(因为你必须使用 webpack 来打包你的 bundle.js)。诸如 CSS 导入、require vs import 之类的东西突然开始咬你(这在没有 webpack 的默认 React 应用程序中不是这种情况)。

SSR 的一般模式如下所示。服务请求的 Express 服务器:

const app = Express();
const port = 8092;

// This is fired every time the server side receives a request
app.use(handleRender);
function handleRender(req, res) {
    const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    console.log('fullUrl: ', fullUrl);
    console.log('req.url: ', req.url);

    // Create a new Redux store instance
    const store = createStore(reducerFn);

    const urlToRender = req.url;
    // Render the component to a string
    const html = renderToString(
        <Provider store={store}>
            <StaticRouter location={urlToRender} context={{}}>
                {routes}
            </StaticRouter>
        </Provider>
    );
    const helmet = Helmet.renderStatic();

    // Grab the initial state from our Redux store
    const preloadedState = store.getState();

    // Send the rendered page back to the client
    res.send(renderFullPage(helmet, html, preloadedState));
}

我对刚开始使用 SSR 的人们的建议是提供静态 html。您可以通过运行 CSR SPA 应用获取静态 html:

document.getElementById('root').innerHTML

别忘了,使用 SSR 的唯一原因应该是:

  1. 搜索引擎优化
  2. 加载速度更快(我会打折扣)

破解:https://medium.com/@gagan_goku/react-and-server-side-rendering-ssr-444d8c48abfc

【讨论】:

    【解决方案2】:

    对于给定的网站/网络应用程序,您可以使用 react client-sideserver-sideboth。 p>

    客户端

    在这里,您完全在浏览器上运行 ReactJS。这是最简单的设置,包括大多数示例(包括http://reactjs.org 上的示例)。服务器呈现的初始 HTML 是一个占位符,一旦所有脚本加载,整个 UI 就会在浏览器中呈现。

    服务器端

    在这里将 ReactJS 视为服务器端模板引擎(如玉石、车把等)。服务器呈现的 HTML 包含应有的 UI,您无需等待任何脚本加载。您的页面可以被搜索引擎索引(如果不执行任何 javascript)。

    由于 UI 是在服务器上呈现的,因此您的任何事件处理程序都不会工作并且没有交互性(您有一个静态页面)。

    两者

    这里,初始渲染在服务器上。因此,浏览器接收到的 HTML 具有应有的 UI。加载脚本后,将再次重新渲染虚拟 DOM 以设置组件的事件处理程序。

    在这里,您需要确保重新渲染完全相同的虚拟 DOM(根 ReactJS 组件),并使用您在服务器上渲染时使用的 props。否则,ReactJS 会抱怨服务器端和客户端的虚拟 DOM 不匹配。

    由于 ReactJS 在重新渲染之间区分虚拟 DOM,因此真实 DOM 不会发生变异。只有事件处理程序绑定到真正的 DOM 元素。

    【讨论】:

    • 所以在“两者”的情况下,我需要编写两次相同的代码“一次用于服务器渲染,一次用于在客户端重现此 DOM?对吗?
    • 您需要运行两次相同的代码。一次在服务器上,一次在客户端上。但是,您需要编写组件以考虑到这一点 - 例如您不应该在componentWillMount() 中进行任何异步数据获取,因为它将同时运行客户端和服务器。您还需要一种策略,用于在服务器上预先获取数据并使其可用于客户端的初始渲染,以确保获得相同的输出。
    • 您还可以使用typeof window == "undefined"检查正在执行的代码是在服务器端还是在客户端,然后相应地获取您的数据。
    • 您是否有适合您实施的示例的链接?
    • @IanW 通常在这种情况下,服务器返回的 HTML 非常“简单”,只需导入您的 JavaScript 和样式并包含 React 将写入的 &lt;div&gt;
    【解决方案3】:

    图片来源:Walmart Labs Engineering Blog

    注意:SSR(服务器端渲染)、CSR(客户端渲染)。

    与 SSR 的主要区别在于,服务器对客户端浏览器的响应包括要呈现的页面的 HTML。 同样重要的是要注意,尽管使用 SSR,页面呈现速度更快。在下载 JS 文件并且浏览器执行 React 之前,该页面不会准备好进行用户交互。

    一个缺点是 SSR TTFB(到第一个字节的时间)可能会稍长一些。可以理解,因为服务器需要一些时间来创建 HTML 文档,这反过来又会增加服务器的响应大小。

    【讨论】:

      【解决方案4】:

      我实际上很想知道同样的研究,虽然您正在寻找的答案在 cmets 中给出,但我觉得它应该更突出,因此我正在写这篇文章(一旦我可以来,我会更新找到更好的方法,因为我发现解决方案至少在架构上存在问题)。

      您需要在编写组件时考虑两种方式,因此基本上将if 开关放置在任何地方以确定您是在客户端还是服务器上,然后作为数据库查询(或服务器上的任何适当的)或 REST 调用(在客户端上)。然后,您必须编写生成数据的端点并将其公开给客户端,然后就可以了。

      再次,很高兴了解更清洁的解决方案。

      【讨论】: