推荐阅读
今天不谈 SEO,我们梳理前端的发展历程,来看看我们为什么需要 react server component。
以下代码基本是伪代码
<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+)加载完成并执行后,才能看到内容,用户体验很糟糕。
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,完成水合过程,就能执行相应交互了。
诚然,服务端渲染能让我们立即看到东西,但是需要等到 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
我们平时写代码的时候,可以:
"use client"
)<a>
标签而非 onClick
+ route
form + action
而非 onClick
如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。
对于转载作品,如需二次转载,请遵循原作许可。