关于javascript:React-RFC-Server-Components是什么有啥用

36次阅读

共计 3720 个字符,预计需要花费 10 分钟才能阅读完成。

转载自:魔术师卡颂 公众号

12 月 21 日,React团队颁布了一个新的提案Server Components

随同这个提案同时收回的,还有一个小时的视频解说、可供运行的 Demo、详尽的介绍。

可见,React团队很器重这个提案。本文会从如下方面解说:

  • Server Components是什么
  • Server Components解决了什么问题

ServerComponent 是什么

一句话概括:

Server Components是在服务端运行的 React 组件。

咦?这和 服务端渲染(SSR)有什么区别?

相比 SSR 将组件在服务端渲染成填充内容的 HTML 字符串,并在客户端 hydrate 后应用。Server Components更像咱们的在客户端写的一般组件一样,只不过他的运行环境是服务端。

咱们能够将组件依照性能分为:

  • 提供数据的 容器组件
  • 渲染数据并提供数据交互的 交互组件

举个例子,Note组件是 容器组件 ,他负责申请并缓存数据。NoteEditor 是渲染 note 数据并执行用户交互的 交互组件

function Note(props) {const [note, setNote] = useState(null);
  useEffect(() => {fetchNote(props.id).then(noteData => {setNote(noteData);
    });
  }, [props.id]);
  
  if (note == null) {return "Loading";} else {return <NoteEditor note={note}/>
  }
}

如例子所述,咱们能够通过在 useEffect 中发动申请并将返回的数据保留在 state 中。

这种 「申请 - 渲染」 模式会遇见被称为 waterfall 的问题:

就像一节一节的瀑布往下流水,NoteEditor须要期待 Note 申请 note 胜利后能力开始渲染。

交互组件 依赖的数据源越多,waterfall问题会更显著。

实践上,如果 React 足够聪慧,就能在 服务端 执行 容器组件 的渲染逻辑,在 客户端 执行 交互组件 的渲染逻辑。

依照这样的理念,如下这棵齐全在客户端渲染的组件树:

能够拆分为:在 服务端 运行的 容器组件 和在 客户端 运行的 交互组件

其中在服务端运行的 容器组件 就是Server Component

ServerComponent 的意义

既然 ServerComponent服务端 运行,人造更靠近各种IO(申请数据库、读取文件、缓存 …)。

下面的例子齐全能够间接从 数据库 获取 note 数据,同时借助Suspense,采纳同步的写法。

function Note(props) {const note = db.notes.get(props.id);
  if (note == null) {return "Loading";}
  return <NoteEditor note={note}/>
}

人造更靠近后端

任何其余数据源只须要通过 React 提供的 API 简略封装,使其反对 Suspense,就能接入ServerComponent 中。人造更靠近后端。

解决 waterfall

区别于 SSR 传输的 HTML 字符串。ServerComponent会将 Note 组件及其从 IO 申请到的数据序列化为相似 JSX 的数据结构,以 的模式传递给前端:

客户端在运行时间接获取到填充了数据的 ,并借助 Concurrent Mode 执行 流式 渲染。

0 打包体积

假如咱们开发一款 MD 编辑器。服务端传递给前端 MD 格局的字符串。

咱们须要在前端引入将 MD 解析为 HTML 字符串的库。这个库就有 206k。

import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)
function NoteWithMarkdown({text}) {const html = sanitizeHtml(marked(text));
  return (/* render */);
}

通过 ServerComponent 咱们怎么解决这个问题呢?

只须要简略将 NoteWithMarkdown 标记为 ServerComponent,将引入并解析MD 这部分逻辑放在 服务端 执行。

ServerComponent并不会减少前端我的项目打包体积。这个例子中,一次性为咱们缩小了前端 206K (63.3K gzipped)的打包体积以及解析 MD 的工夫。

主动代码宰割

通过应用 React.lazy 能够实现组件的 动静 import。之前,这须要咱们在切换组件 / 路由时手动执行。在 ServerComponent 中,都是主动实现的。

在下面动图中,左侧列表是ServerComponent,当点击其中卡片时,组件对应数据会动静加载。

更好的 ahead-of-time (AOT)优化

Vue作为一门应用 模版语言 的框架,模版语言 的固定写法使其能在编译时针对模版内容作出优化。

因为 JSX 仅仅是 JS 的语法糖,React很难在编译时做出优化。

ServerComponent对组件提出了更多限度(不能应用 useStateuseEffect…)。这些限度从侧面为AOT 提供更多优化线索。

ServerComponent 的应用

上面咱们通过改写一个 记事本 组件解说 ServerComponent 的应用:

// Note.js 
import fetchData from './fetchData'; 
import NoteEditor from './NoteEditor';
function Note(props) {const {id, isEditing} = props;
  const note = fetchData(id);
  
  return (
    <div>
      <h1>{note.title}</h1>
      <section>{note.body}</section>
      {isEditing 
        ? <NoteEditor note={note} />
        : null
      }
    </div>
  );
}

Note组件的次要性能是依据 props 传入的 id 申请对应的 note 数据。

NoteEditor用于展现及批改note

其中 fetchData 办法用于获取数据,数据的加载中状态由组件外的 Suspense 实现。

能够看到,交互局部由 NoteEditor 实现,Note次要性能是获取并传递数据。

接下来咱们将 Note 变为ServerComponent

// 留神????
// Note.server.js - Server Component
// 留神????
import db from 'db.server'; 
// 留神????
import NoteEditor from './NoteEditor.client';
function Note(props) {const {id, isEditing} = props;
  const note = db.posts.get(id);
  
  return (
    <div>
      <h1>{note.title}</h1>
      <section>{note.body}</section>
      {isEditing 
        ? <NoteEditor note={note} />
        : null
      }
    </div>
  );
}

有 3 点须要留神的改变,咱们顺次理解下:

  1. Note.js文件名改为 Note.server.js 代表这是Server Component
  2. Note.server.js运行于服务端,咱们不须要客户端的 fetchData 办法,能够间接拜访数据库,所以这里调用 db.server 提供的办法
  3. NoteEditor用于展现及批改 note。这是由客户端用户的交互管制的,所以将文件名改为NoteEditor.client 代表这是个Client Component

总结

太阳底下没有新鲜事。晚期前端交互简略,仅仅作为服务端的 View 层。

随着前端交互变简单,呈现了前端框架主导的客户端渲染(CSR)。

为了解决首屏渲染速度、SEO 问题,呈现了服务端渲染(SSR),又回到了已经作为 View 层的终点,只不过管制的粒度更细。

ServerComponent提案的呈现,预示着 React 的长远目标:将对 View 层的管制细化到组件级别。

为什么是 「长远目标」ServerComponent 落地的大前提是 Concurrent Mode 生产环境稳固,让咱们一起期待 2021 年吧。

参考资料

[1] 视频解说: https://www.youtube.com/watch…

[2] Demo: https://github.com/pomber/ser…

正文完
 0