Next13
上周的Next Conf带来劲爆的turbopack,相信不少小伙伴都关注到了。其实这次的Next Conf还有一大主角,Next.JS 13 - 我愿称之为真.React18。
在Next13中,许多React18的特性都得到了解锁:
- 服务端React组件: (RSC)
- 原生支持异步的服务端组件: Async Server Component
- 实验中的Hook:use
- 新的SSR结构:流式HTML + Suspense
- cache api (React团队RFC文案还未提出的新API)
本文主要介绍前三个内容,体验下Next13服务端组件带给前端的冲击(可能开启真的大前端时代了)
如何开始体验Next13
NextJS提供完整的文档,目前还在Beta状态, beta.nextjs.org/docs/gettin…
使用下面Cli脚本马上开始体验Next13
npx create-next-app@latest --experimental-app
React服务端组件
先看Next13的重头戏,也是2020年React团队新开的坑RSC,Next13中终于可以使用了。
在Next13中,app目录下的组件默认都是服务端组件,在服务器中渲染好再返回到浏览器(默认没有交互,不需要水合)。有了服务端组件,我们可以在React应用中用同一套React语法,混合使用服务端组件和客户端组件。
为什么需要服务端组件
- React服务端组件中可以使用Nodejs的各种能力
- 在服务端组件中发起请求,可以在请求返回HTML前,就完成数据的读取。相比原来JS应用从服务端传送JS资源到客户端,React完成渲染后再向服务端请求数据,大幅减少FCP(首次内容绘制时间)
- 有效减少传送到浏览器的JS包体积
- 传统SSR的各种优势(SEO友好,首屏渲染快)
异步服务端组件
在服务端组件中,可以直接在组件中使用async/await,获取到数据后,传给客户端组件。这也是Next13推荐使用这种方式读取数据。
async function getData() {
const res = await fetch('https://api.example.com/...');
// 返回值不需要序列化 可以return Date, Map, Set.
return res.json();
}
export default async function Page() {
const name = await getData();
// 数据传递到客户端组件,会被序列化
return <ClientCompoent name={name} />;
}
通过异步服务端组件,我们可以复用一切Nodejs中已经存在的能力,延展React组件的边界,如:
- 充当BFF层,来向后端获取数据
- 使用RPC向后端获取数据
- 直接使用ORM框架例如prisma,从DB中获取数据 (小应用一把梭,新时代的PHP)
- 直接从消息队列中消费数据,例如使用KafkaJS从Kafka中获取数据
目前的限制
- 服务端组件中渲染另一个异步服务端组件目前会有TS告警,因为async函数返回值是Promise,当前Promise的值不能作为JSX去渲染,需要React组件TS类型更新支持
- 不能在客户端组件去渲染服务端组件(所以客户端组件应该尽量靠近整个应用的叶子节点)
客户端组件
客户端组件即原来我们写的运行在浏览器的React组件,需要'use client'标识。
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
新的Hook use
Next13的客户端组件中,可以使用use同步式的去处理异步方法,对标服务端组件的await。
如下面的getDate这个异步函数,既可以在服务端组件中通过await拿到数据,也能复用到客户端组件中通过use去拿到数据
async function getData() {
const res = await fetch('https://api.example.com/...');
return res.json();
}
'use client';
export default function Page() {
const name = use(getData());
return <h1>{name}</h1>;
}
服务端组件和客户端组件应该怎么选择?
| 用途 | 服务端组件 | 客户端组件 |
|---|---|---|
| 从服务端获取数据 | ✅ | 尽量不要 |
| 读取服务端静态资源 | ✅ | ❌ |
| 保存敏感数据,如tokens,API,keys | ✅ | ❌ |
| 大体积的JS依赖 | ✅ | ❌ |
| 交互和事件监听 | ✅ | ❌ |
| 状态和生命周期(useState, useReducer, useEffect()) | ❌ | ✅ |
| 浏览器API | ❌ | ✅ |
| 自定义Hooks涉及状态和生命周期 | ❌ | ✅ |
| React类组件 | ❌ | ✅ |