ReactJS服务器端渲染与客户端渲染


120

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

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


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

Answers:


108

对于给定的网站/ Web应用程序,您可以在客户端服务器端同时使用二者

客户端

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

服务器端

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

由于UI是在服务器上呈现的,因此您的事件处理程序均无法正常工作,并且没有交互性(您拥有静态页面)。

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

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

由于ReactJS在重新渲染之间扩散虚拟DOM,因此真实DOM不会发生突变。仅事件处理程序绑定到实际DOM元素。


1
因此,在“两者”的情况下,我需要编写两次相同的代码“一个用于服务器渲染,一个用于在客户端上重现此DOM?”
Simcha 2014年

10
您需要运行两次相同的代码。一次在服务器上,一次在客户端上。但是,您需要编写组件以考虑到这一点-例如,您不应在中进行任何异步数据获取componentWillMount(),因为它将同时在客户端和服务器上运行。您还需要一种策略,用于在服务器上预先获取数据并使其可用于客户端的初始呈现,以确保获得相同的输出。
乔尼·布坎南

3
您还可以使用来检查正在执行的代码是在服务器端还是在客户端typeof window == "undefined",然后相应地获取数据。
Gautham Badhrinathan 2014年

您是否有一个适合您实施的示例的链接?
Sawtaytoes

1
@IanW通常,在这种情况下,服务器返回的HTML非常“裸露”,只需导入您的JavaScript和样式,并包含<div>React将写入其中的。
马特·荷兰

48

图片来源:沃尔玛实验室工程博客

固态继电器

企业社会责任

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

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

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


4

我实际上很想知道相同的研究,虽然您正在寻找的答案已在评论中给出,但我认为它应该更加突出,因此我正在写这篇文章(一旦我能提出一个建议,我将对其进行更新。更好的方法,因为我发现解决方案在架构上至少有问题)。

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

同样,很高兴了解更清洁的解决方案。


2

是使用两种单独的方法来构建应用程序,还是可以将它们一起使用?

它们可以一起使用。

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

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

如果您只是从SSR开始,我建议您从简单开始,SSR很快就会变得非常复杂。在服务器上构建html意味着无法访问诸如窗口,文档之类的对象(您在客户端上拥有这些对象),无法合并异步操作(开箱即用),并且通常需要进行大量代码编辑才能使您的代码与SSR兼容(因为您必须使用webpack来打包bundle.js)。诸如CSS导入之类的要求vs导入之类的事情突然开始对您造成困扰(在没有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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.