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 条评论
登录 后参与评论

相关文章

来自专栏分享达人秀

日历视图CalendarView和定时器Chronometer

上一期学习了AnalogClock、DigitalClock和TextClock时钟组件,本期继续来学习日历视图CalendarView和定时器Chro...

2316
来自专栏编程

如何提升Web页面的性能,HTML和css代码优化!

怎么进步Web页面的功用,许多开发人员从多个方面来下手如JavaScript、图画优化、服务器配置,文件压缩或是调整CSS。 很显然HTML 已经达到了一个瓶颈...

3695
来自专栏BestSDK

年薪30万的前端面试题,你能答对几道?|附答案

HTML面试题 1.XHTML和HTML有什么区别 HTML是一种基本的WEB网页设计语言,XHTML是一个基于XML的置标语言 最主要的不同: XHTML 元...

4286
来自专栏极乐技术社区

微信小程序那点事:特性总结

一、微信小程序运行环境 1、完全封闭的环境不等于浏览器环境 2、WXML/WXSS/JS格式 3、WXML 不等于 HTML 4、WX...

2226
来自专栏前端说吧

vue - v-model实现自定义样式の多选与单选

来不及研究为什么,我先直接在原来项目上赶紧建了一个test页面,先赶紧实现我的这种设想:

4381
来自专栏谦谦君子修罗刀

RN手势

React Native框架底层的手势响应系统提供了响应处理器,PanResponder API将这些手势响应处理器再次进行封装,便于开发者对手势进行处理。 ...

33612
来自专栏小程序之家

如何使用小程序表单组件

上一篇文章中,我们给大家介绍了小程序的视图容器及基础内容组件,该组件主要应用是输出内容。接下来这篇文章中,我们将继续介绍小程序最常用的表单组件,该组件主要应用是...

2773
来自专栏Web 开发

WordPress主题修改之Html5语义化

Html5最大的特点在于多媒体和移动互联网方面,小弟不才,对那些了解不多,本次修改仅仅是为了那么一点点语义化。

1280
来自专栏Golang语言社区

H5一二事 - 要饭的

先回顾一下WEB技术的几个阶段 那么H5肯定不是多了一些标签就完事了,H5也跟酷炫没什么关系,那是CSS3的事情,它更多的职责是功能,而不是外观,是JavaSc...

3098
来自专栏达摩兵的技术空间

h5标签入门

1131

扫码关注云+社区

领取腾讯云代金券