域名 AXUM.RS 将于 2025 年 10 月到期。我们无意再对其进行续费,如果你有意接续这个域名,请与我们取得联系。
  • AXUM.RS 现仅需人民币 3000 元(大写:叁仟元整。接受适度议价
  • 按照行业规则,AXUM.RS 到期后,大概率会进入长时间的赎回期,该期间内,如果你想拥有该域名,将要付出高额的费用
  • 我们已启用 AXUM.EU.ORG 域名,并将持续运营
  • 仅接受微信或支付宝交易
如果你对 AXUM.RS 有兴趣,请和我们进行联系:

React: SEO挑战、服务端渲染及本地存储

为什么说 SEO 是 React 应用的最大挑战

我们来做个实验:将本课程 React 课程第一章最后使用 vite 生成的 React 进行构建,然后看一下构建后的内容。先来看一下我们的源码怎么写的:

import React from 'react';

function App() {
  return <h1>你好,axum中文网 - 来自 react 的问候</h1>;
}

export default App;

非常非常简单,就一行硬编码进去的文字。现在,让我们构建它:

yarn build

构建好之后,会将目标文件放在 dist 目录下。打开 dist/index.html,这是构建好的最终的 HTML 文件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React</title>
    <script type="module" crossorigin src="/assets/index.7b12dfb4.js"></script>
  </head>
  <body>
    <div id="root"></div>
    
  </body>
</html>

握了个大草,依然只有一个 <div id="root"></div>。我们在组件里写的那个 <h1>你好,axum中文网 - 来自 react 的问候</h1> 跑去哪里了?

你会看到,在这个 HTML 里有一行引入 JS 代码的标签:<script type="module" crossorigin src="/assets/index.7b12dfb4.js"></script> ,是的,我们写的组件(包括本例这种硬编码进去的文本内容)全部被打包进了 JS 文件里。

原因也很简单,我们是用 JSX 来开发组件的,JSX 的本质是 React.createElement()语法糖, 这是一个由 React 提供的 Javascript 函数,自然我们开发的组件全被视为对 React.createElement() 调用的 Javascript 代码了。

HTML 里空空如也,内容和数据全跑到 JS 里去了,这是对 SEO 最大的挑战——几乎不要奢望SEO了。

本节代码:axum-rs-react-no-seo

服务端渲染(Server-Side Rendering)

由于它的缩写过于敏感,为防止被误杀,本站将一直使用「服务端渲染」而不用它的三字母缩写

由于它的缩写过于敏感,为防止被误杀,本站将一直使用「服务端渲染」而不用它的三字母缩写

有没有可能把组件直接渲染成普通的HTML标签,以利于SEO?可以的,服务端渲染就行,而且 React 官方就提供了相应的功能。下面代码是我们一直在用的,一个典型的 React 入口文件:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

第2行:import ReactDOM from 'react-dom/client',我们是从 react-dom/client 导入的 ReactDOM

  • 大胆猜测,是不是还有 react-dom/server
  • 小心求证:是的。官方文档在这里

本课程不使用 React 提供的服务端渲染,而是使用 NextJS 来更灵活的处理各种渲染模式。

惊天大BUG!我要上报给官方,少说能拿个几万美刀!

同学,醒醒!你缺的不仅仅是美刀,更是缺少对基础知识的理解!

要避免这位同学遇到的问题,那就需要将那些数据进行持久化。

前端数据的持久化

在后端,我们有很多种途径对数据进行持久化:写入到文件、保存到数据库等等。而在前端,我们可以利用 HTML 5 提供的 Storage API实现。

有两种 Storage

它们提供的 API 一样,只是存储数据的持续时间不同。会话存储基本上就是关闭浏览器,数据就会自动被清除;而本地存储则是,除非手动删除,否则它一直都在。

上面给出的文档链接里有示例代码,我们来看一下:

再说一遍,它们的API是一样的,把上面代码中的 sessionStorage 改成 localStorage 就是本地存储

再说一遍,它们的API是一样的,把上面代码中的 sessionStorage 改成 localStorage 就是本地存储

本地存储的 React hook

定义一个 hook

使用 hook

function App() {
  // Similar to useState but first arg is key to the value in local storage.
  const [name, setName] = useLocalStorage("name", "Bob");

  return (
    <div>
      <input
        type="text"
        placeholder="Enter your name"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  );
}

以上代码来自这里

以上代码来自这里

你可以根据自己的需求把上面的 hook 进行优先、扩展,以期与你的需求更加契合。

是时候撒花了,恭喜你完成了我们这个专题的第一个子专题。下一章我们将开始 NextJS 的学习,准备好了吗?

要查看完整内容,请先登录