抛开 SEO,我们为什么需要 react server component
今天不谈 SEO,我们梳理前端的发展历程,来看看我们为什么需要 react server component。
以下代码基本是伪代码
刀耕火种:html + js 一把梭
<html>
<body>
<header>xxx</header>
<main>xxx</main>
<footer>
<div id="time">loading...</div>
</footer>
<script src="index.js" />
</body>
</html>
// index.js
const timeElem = document.querySelector("#time")
const now = new Date().toLocaleString()
timeElem.innerText = now
html + js + css
三剑客的时候,我们通常会把 js 放到 html 最底部,防止阻碍页面的加载。
这时候,运行很快,但不便于前端组织代码。
鸟枪换炮:单页面一把梭
<html>
<body>
<div id="app" />
<!-- 构建时会将 js 注入到这里 -->
</body>
</html>
单页面的时候,所有的页面内容和逻辑都在 js 里,html 只包含一个 js 入口和一个根元素(div#app
),js 加载完成后运行,渲染出所有内容,插入到根元素(div#app
)中。
这时候,路由一般由前端来控制,组织代码是方便了,但是由于所有内容都在 js 中,用户加载完一个 html 完全白屏,什么也看不到,必须要等到 js(size 通常 1M+)加载完成并执行后,才能看到内容,用户体验很糟糕。
再快一点:服务端渲染
tsx 源码(示意)
function Time() {
const now = new Date().toLocaleString()
return <div id="time" onClick={xxx}>
{now}
</div>
}
function App() {
return <>
<header>xxx</header>
<main>xxx</main>
<footer>
<Time />
</footer>
</>
}
构建后的代码(示意)
-
index.html
<html> <body> <header>xxx</header> <main>xxx</main> <footer> <!-- js 执行后将会替换掉下面这个 div --> <div data-id="time" /> </footer> <script src="index.js" /> </body> </html>
-
index.js
const timeElem = document.querySelector("[data-id='time']") const now = new Date().toLocaleString() timeElem.innerText = now // 为元素绑定事件,即 hydrate 水合 timeElem.onclick = xxx
服务端渲染和单页面类似,但是考虑到 js 中有一些逻辑并不依赖客户端(浏览器),所以可以先在服务端执行,渲染出尽可能多的内容,直接写到 html 中,再发送给客户端。
客户端接收到的内容不再是空的 html 了,而是包含部分 DOM 结构,用户能立即看到东西,只是不能交互,等到客户端加载完 js,完成水合过程,就能执行相应交互了。
精益求精:server action
诚然,服务端渲染能让我们立即看到东西,但是需要等到 js 加载完了才能交互。有没有办法在 js 没加载的时候就能交互呢?server action 可以。
function App() {
const serverAction = async (formData: FormData) => {
"use server"
const name = formData.get("name")
// do something
}
return <form action={serverAction}>
<input name="name" />
<button type="submit">提交</button>
</form>
}
react 会将 serverAction
代码放在服务端执行,即使尚未加载 js,或用户禁用了 js,浏览器也原生支持表单提交,具体可查看 react 文档 server-actions-and-mutations
More
我们平时写代码的时候,可以:
- 适当多地让代码在服务端执行(少用
"use client"
) - 适当多地拆分粒度,客户端组件尽量出现在 DOM 树的叶子部分
- 这样可以降低需要向客户端传输的 js 的尺寸
- 尽可能使用浏览器原生支持的功能
- 使用
<a>
标签而非onClick
+route
- 使用
form + action
而非onClick
- 使用