Hi! 👋

有趣的next.js服务端组件

Next.js 13 添加了许多值得注意且颠覆性的东西;但是,很大一部分仍然是 Beta阶段。尽管如此,Beta 功能为我们提供了关于 Next.js 未来将会被如何塑造的重要信号,即使你现在并不打算在你的项目里使用它。

默认创建服务端组件,如需更改客户端组件需要显式声明:

Next.js 13 引入了app文件目录,这是一种在考虑 React Server Components的情况下构建 Next.js 应用程序的全新方式。app目录下构建的组件默认是React Server Components,如果要构建客户端组件必须显式添加 'use client'

什么是 React 服务器组件?

React Server Components是在服务器上呈现的组件。React Server Components利用服务器的优势功能给客户端提供更优质的体验。

服务器组件最常见的用例是获取数据并根据服务器上的数据呈现在你的组件内。

你要考虑放入服务器组件的内容是:

获取数据(利用服务器的超高速连接)
访问后端资源或文件系统
不需要客户端交互的具有大量依赖项的组件

💡注意 React Server Components不能包含任何客户端交互,,因为您需要提前考虑如何最好地分发组件,但目标是将尽可能多的组件移至可预测且性能更高的服务器。
仅客户端调用的常见示例:useState,useEffect,onClick

为什么需要 React 服务器组件?

第一个原因是服务器组件对应用程序的整体包大小贡献为零。这意味着客户端的下载文件大小更小,从而使您的页面更快。

如果您有需要使用但客户端不需要的包,这个好处会非常有用。将这些依赖项完全保留在服务器端意味着减少客户端的下载。首屏加载体验会更佳

如上所述,另一个很大的好处是您的代码在功能强大的服务器上运行,希望也更接近数据。将计算推送到服务器可以为移动设备上的访问者带来很大的不同。

一个示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
C:.
│ .env
│ .eslintrc.json
│ .gitignore
│ next-env.d.ts
│ next.config.js
│ package-lock.json
│ package.json
README.md
│ tsconfig.json

├─.vscode
│ settings.json

├─app
│ │ globals.css
│ │ head.tsx
│ │ layout.tsx
│ │ page.tsx
│ │
│ ├─client
│ │ page.tsx
│ │
│ ├─degenerate
│ │ client.tsx
│ │ nested-server.tsx
│ │ page.tsx
│ │
│ ├─mixmatch
│ │ client.tsx
│ │ nested-server.tsx
│ │ page.tsx
│ │
│ └─server
│ page.tsx

└─public
favicon.ico
vercel.svg

创建我们的第一个服务器组件:

1
2
3
4
5
6
7
8
9
10
// app/server/page.tsx
export default function Server() {
console.log('服务器页面已渲染:这应该只打印在服务器上');
return (
<div>
<h1>Server Page</h1>
<p>My secret key: {process.env.MY_SECRET_ENV}</p>
</div>
);
}

如果您访问/server路由,无论是通过浏览器加载还是客户端路由,都只会在服务器控制台中看到日志行,而不会在浏览器控制台中看到。环境变量值也是从服务器端获取的。

查看浏览器中的网络流量,会看到服务器组件的内容是通过远程调用加载的,该调用返回渲染结果的 JSON 数据的八位字节流:

渲染服务器组件实际上是一个 API 调用,以获取序列化的虚拟 DOM,然后在浏览器中实现它。

最重要的是,服务器组件用于呈现非交互式内容,因此没有事件处理程序、没有 React hooks,也没有仅限浏览器的API。

最显着的好处是可以自由访问服务器组件中的任何后端资源和机密。它更安全(数据不会泄漏)和更快(代码不会泄漏)。

客户端组件

要做一个客户端组件,需要显式声明use client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// app/server/page.tsx
'use client';

import { useEffect } from 'react';

export default function Client() {
console.log(
'客户端页面渲染:这应该只在ssr期间打印在服务器上,在路由时打印在客户端上'
);

useEffect(() => {
console.log('客户端组件渲染');
});

return (
<div>
<h1>Client Page</h1>
</div>
);
}
}

这提供了与以前的 Next.js 版本类似的行为。当页面首次加载时,它是由 SSR 渲染的,因此在服务器控制台中看到第一个日志;在客户端路由期间,两条日志消息都将出现在浏览器控制台中。

到底有什么区别

Server Component 和 SSR 最大的区别之一是 SSR 是页面级别的,而 Server Component 顾名思义是组件级别的。这意味着您可以根据需要在渲染树中混合和匹配服务器和客户端组件。

服务器组件可能会降级退化

如果将服务器组件直接引入到客户端组件中,它会默认降级退化为客户端组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app/degenerate/page.tsx

import Client from './client';

export default function DegeneratePage() {
console.log('降级页面渲染');
return (
<div>
<h1>Degenerated Page</h1>
<div className="box-blue">
<Client message="A message from server" />
</div>
</div>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// app/degenerate/client.tsx

'use client';

import NestedServer from './nested-server';

export default function Client({ message }: { message: string }) {
console.log('客户端组件渲染');

return (
<div>
<h2>Client Child</h2>
<p>Message from parent: {message}</p>
<div className="box-blue">
<NestedServer />
</div>
</div>
);
}
1
2
3
4
5
6
7
8
9
10
// app/degenerated/nested-server.tsx
export default function NestedServer() {
console.log('嵌套服务端组件渲染');
return (
<div>
<h3>降级服务端组件</h3>
<p>内容</p>
</div>
);
}

如果您查看日志,会看到NestedServer已经“降级退化”并且由浏览器呈现。

这是一个未来的趋势么?

Next.js 正在尽其所能将事情转移到服务器端,这正是人们在 2010 年前进行 Web 开发的方式😅。所以现在我们完成了一个完整的循环,但大大改善了开发体验和最终用户体验。

对于终端用户来说,这是一个明显的胜利,因为服务器端的计算速度更快、更可靠。结果将是更快的第一个内容渲染

对于开发人员而言,模式转变将在精神上带来挑战,并伴随着混乱、错误和反模式。这将是一段地狱般的旅程。

🚀 关于我


👩‍💻 🧠👯‍♀️🤔 💬 📫😄 ⚡️