抛开 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

如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。

对于转载作品,如需二次转载,请遵循原作许可。