专栏首页IMWeb前端团队React16中的服务端渲染(译)

React16中的服务端渲染(译)

本文作者:IMWeb zzbozheng 原文出处:IMWeb社区 未经同意,禁止转载

React 16发布了。 React 16有很多令人兴奋的新东西(尤其是Fiber),而且React 16对服务器端渲染所做了许多改进,让我们深入剖析React16的服务端渲染有什么不一样。

React 15 SSR是如何工作的

首先,我们先回顾一下React 15的服务端渲染,为了实现SSR,你可能会用nodejs框架(Express、Hapi、Koa)来启动一个web服务器,接着调用 renderToString 方法去渲染你的根组件成为字符串,最后你再输出到 response。

// using Express
import { renderToString } from "react-dom/server"
import MyPage from "./MyPage"
app.get("/", (req, res) => {
  res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
  res.write("<div id='content'>");  
  res.write(renderToString(<MyPage/>));
  res.write("</div></body></html>");
  res.end();
});

然后,在客户端bootstrap代码,再次使用render方法来生成HTML:

import { render } from "react-dom"
import MyPage from "./MyPage"
render(<MyPage/>, document.getElementById("content"));

讲道理,客启端渲染会使用服务端渲染好的HTML,而不是去更新DOM。

那么,服务端渲染在React 16会有不同呢?

React 16 向后兼容

React开发团队有强烈的意愿表示会向后兼容,如果你的代码能够在React 15中运行,那么也可以在React 16中运行,并且不会出现任何弃用警告,正如上面的代码,他可以很好地运行在React 15 和 React 16 中。如果你在App中使用React 16并且发现错误,请在这里提issue,这将会帮助核心团队修复React 16的各种错误。

render() 变为 hydrate() 当你将直出代码从React 15升级到React 16时,你有可能会在浏览器看到以下警告:

事实证明React 16现在有两种不同的客户端渲染方法:当您仅在客户端呈现内容时,使用render() 方法,如果你在服务端渲染结果之上再次渲染则使用hydrate()方法。因为React向后兼容,在React 16中,render()方法会继续可用于服务端渲染。但为了不出现警告信息你最好使用hydrate()方法来代替render():

import { hydrate } from "react-dom"
import MyPage from "./MyPage"
hydrate(<MyPage/>, document.getElementById("content"))

React 16可以处理数组、字符串和数值 在React 15中,,一个组件的render方法必须返回单一的React元素。在React 16, 客户端渲染和服务端渲染允许组件的render 方法返回字符串,数值或者是一个元素数组。

所以,你可以在服务端渲染中写类似以下的代码

class MyArrayComponent extends React.Component {
  render() {
    return [
      <div key="1">first element</div>, 
      <div key="2">second element</div>
    ];
  }
}
class MyStringComponent extends React.Component {
  render() {
    return "hey there";
  }
}
class MyNumberComponent extends React.Component {
  render() {
    return 2;
  }
}

您甚至可以将一个字符串,数字或一组组件传递给顶层的renderToString方法:

res.write(renderToString([
      <div key="1">first element</div>, 
      <div key="2">second element</div>
    ]));
// it’s not entirely clear why you would do this, but it works!
res.write(renderToString("hey there"));
res.write(renderToString(2));

这样你就可以不用为React组件添加div和span,从而使减少HTML的体积。

React16 会更快

说到性能,尽管我们对每一个地方都做到了最佳实践,但是生产环境中的React服务器端渲染依然很慢。在React 16中,跨多个不同版本的Node的服务器端呈现出现惊人的速度:

当将React 15与process.env进行比较时,节点4大约有2.4倍的改进,节点6的性能提升了3倍,而新的Node 8.4版本的增加了3.8倍。 如果您与React 15进行比较而不进行编译,则React 16在最新版本的Node中的SSR中有一个完整的数量级增益。

为什么React 16 SSR比React 15快得多? 在React 15中,服务器和客户端渲染路径或多或少是相同的代码。 这意味着维护虚拟DOM所需的数据结构都将在服务器呈现时进行设置,即使在对renderToString的调用返回时,vDOM也被丢弃。 这意味着在服务器渲染路径上有很多浪费的工作。

然而,在React 16中,核心团队从头开始重写了服务器渲染器,并且根本没有进行任何vDOM的工作。 这意味着它可以快得多。

我做的测试只是用一个非常简单的递归React组件生成一个span的巨型树,这是一个非常极端的基准,不一定能够反映出真实应用场景。

React 16 支持 Streaming

React 16现在支持直接渲染到节点流。渲染到流可以减少你的内容的第一个字节(TTFB)的时间,在文档的下一部分生成之前,将文档的开头至结尾发送到浏览器。 当内容从服务器流式传输时,浏览器将开始解析HTML文档。

渲染到流的另一个好处是能够响应背压。 实际上,这意味着如果网络被备份并且不能接受更多的字节,则渲染器会获得信号并暂停渲染,直到堵塞清除。 这意味着您的服务器使用更少的内存,并更加适应I / O条件,这两者都可以帮助您的服务器处于具有挑战性的条件。

要使用React 16的渲染流,您需要分别在对应于renderToStringrenderToStaticMarkup的react-dom / server:renderToNodeStreamrenderToStaticNodeStream上调用两个新方法其一。 这些新方法不是返回一个字符串,而是返回一个可读流,一个用于发送字节流的对象的Node Stream类。

当从renderTo(Static)NodeStream返回可读流时,它处于暂停模式,并且没有发生渲染。 只有当您调用read或更有可能将可读流导入到可写流中时,才能启动渲染。 大多数Node Web框架都有一个从Writable继承的响应对象,所以通常可以将Readable传递给响应。

// using Express
import { renderToNodeStream } from "react-dom/server"
import MyPage from "./MyPage"
app.get("/", (req, res) => {
  res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
  res.write("<div id='content'>"); 
  const stream = renderToNodeStream(<MyPage/>);
  stream.pipe(res, { end: false });
  stream.on('end', () => {
    res.write("</div></body></html>");
    res.end();
  });
});

请注意,当我们pipe到响应对象时,我们必须包含可选参数{end:false},以便在渲染器完成时不要自动结束响应。 一旦流完全写入到响应中,我们就可以完成HTML体,并结束响应。

原文: https://hackernoon.com/whats-new-with-server-side-rendering-in-react-16-9b0d78585d67

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • React16中的服务端渲染(译)

    React 16发布了。 React 16有很多令人兴奋的新东西(尤其是Fiber),而且React 16对服务器端渲染所做了许多改进,让我们深入剖析React...

    IMWeb前端团队
  • Why you shouldn`t use Preact, Fast-React, etc. to replace React today

    本文作者:IMWeb nixzheng 原文出处:IMWeb社区 未经同意,禁止转载 生命在于折腾,Coder的折腾就在于造各种轮子。React在前端...

    IMWeb前端团队
  • Why you shouldn`t use Preact, Fast-React, etc. to replace React today

    生命在于折腾,Coder的折腾就在于造各种轮子。React在前端圈大火之后,轮子层出不穷。而其中的一些轮子,由于专注于解决很多人诟病的React过大、过慢的问题...

    IMWeb前端团队
  • React16中的服务端渲染(译)

    React 16发布了。 React 16有很多令人兴奋的新东西(尤其是Fiber),而且React 16对服务器端渲染所做了许多改进,让我们深入剖析React...

    IMWeb前端团队
  • 21个让React 开发更高效更有趣的工具

    有没有想过你的应用程序的哪些包或哪部分代码所占总大小的多少? Webpack Bundle Analyzer可以帮助咱们分析。

    前端小智@大迁世界
  • 2020 年你应该知道的 React 库

    React 已经诞生很久了,自从它诞生开始,围绕组件驱动形成了一个非常全面的生态,但是来自其他编程语言或者框架的开发人员很难找到要构建一个 React 系统的所...

    桃翁
  • 为什么要选择React

    无意比较几大框架的优劣,但是要入手一门框架,对于刚学习的同学而言,学谁的价值最高?是一个绕不开的问题。

    用户6901603
  • 21个让React 开发更高效更有趣的工具

    有没有想过你的应用程序的哪些包或哪部分代码所占总大小的多少? Webpack Bundle Analyzer可以帮助咱们分析。

    Javanx
  • 「首席架构师推荐」React生态系统大集合

    首席架构师智库
  • 【React】653- 22 个让 React 开发更高效更有趣的工具

    英文 | https://dev.to/jsmanifest/22-miraculous-tools-for-react-developers-in-2019...

    pingan8787

扫码关注云+社区

领取腾讯云代金券