内容介绍
本专题假设你已经具备了基本的 HTML 5 、Javascript(ES6) 和 CSS 3 知识。本专题是为了补全 AXUM 全栈开发所需要的技术栈,而不是从零开始的前端课程,如果你还不具备以上知识,请通过其它途径学习完成之后,再来学习本专题。React: 简介与安装
本章将通过编程世界通用的“Hello World”程序,告诉你:创建 React 应用的几种方法、虚拟DOM、JSX以及将 React 挂载到真实 DOM 的步骤。- 支持试读
React:类式组件、函数式组件及state和props
本章将讨论 React 的类式组件、函数式组件以及 React 两个最重要的属性:`state` 和 `props`。 React: 组件的生命周期
本章将讨论 React 组件的常用生命周期。- 支持试读
React: 事件处理、表单处理及受控组件与非受控组件
本章讨论 React 的事件处理,以及表单处理时涉及两个策略:受控组件与非受控组件。 React: 流程控制与key
本章将讨论 React(JSX) 的条件判断和循环。React: 自定义组件及组件通讯
本章我们将正式开启 React 组件之路。虽然我们之前章节的都叫组件,但整个应用只有一个组件,略显单薄。同时,我们还将讨论组件之间如何进行通讯。React: 路由
本章将讨论 React 的路由:通过路由,你可以制作出“多页面”的系统。React: 状态共享
本章将通过一个非常典型的案例来讨论 React 的状态共享:只有登录用户才能看到某些内容。早期的 React 完全依靠其生态中的 redux 等第三方库来实现状态共享;现在 React 提供了官方的 `Context` 来实现这一目的。React: SEO挑战、服务端渲染及本地存储
经过紧张的学习,React 课程终于暂告一个段落了。本章将是一个相对轻松的内容,我们一起探讨一下 React 应用的 SEO 以及为什么需要服务端渲染,同时对 React 课程做个简单的小结。NextJS: 简介与安装
NextJS 是一个 React 框架,它提供了很多有用的功能把 React 的力量发挥地淋漓尽致。本章我们将开始 NextJS 之旅,首先自然是安装它,然后来一个「你好,NextJS」NextJS: 渲染模式和数据获取
趁你现在对我们刚刚讨论的有关 React 和 SEO 的问题还保持有较强的印象,我们先来讨论 NextJS 是如何利用多种渲染模式来应用 SEO 挑战的。NextJS: 内置组件及自动路由
NextJS 既然是 React 的框架,自然提供了一些内置组件来扩展 React。本章将介绍几个常用的 NextJS 内置组件,同时也将介绍 NextJS 的路由系统。NextJS: 开发博客系统
本章我们将使用 NextJS 开发一个小型的博客系统,你将学习到如何从远程服务器获取数据以及数据过滤、NextJS 常用组件的用法、NextJS 的自动路由等功能。Tailwind:简介与响应式设计的基本原则
TailwindCSS 是一款响应式的、移动设备优先的 CSS 工具类框架。本章对响应式布局、移动设备优先、断点等基本概念进行简要说明;并讨论几种安装 tailwind 的方式。Tailwind: 通过小示例体验它
本章通过两个小示例来体验一下 tailwind 的魔力。Tailwind: 默认配置
Tailwind 定义了一系列变量,比如颜色、大小、间距等。本章将介绍 tailwind 的一些默认设置。Tailwind: 撸一个按钮
本章将带你使用 tailwind 撸一个按钮Tailwind: 使用 flex 和 grid 进行响应式布局
本章我们将讨论使用 `flex` 和 `grid` 进行响应式布局,以及为什么不建议再使用 `float` 进行布局。- 支持试读
Tailwind: 撸一个带图标和动画效果的下拉框
本章将使用 tailwind 实现一个没有任何 Javscript 代码的纯 CSS 的下拉框,把应用到导航栏、菜单栏时,也被称为下拉菜单。同时我们将讨论如何在 tailwind 中使用图标,包括图标的进化史:从字体文件到SVG。 Tailwind: 撸一个报价卡片
本章我们将使用 tailwind 撸一个报价卡片。Tailwind: 撸一个响应式的纯CSS导航栏
本章将使用 tailwind 撸一个响应式的、纯 CSS 的导航栏。Tailwind: 集成到React/NextJS
本章将介绍如何将 Tailwind 集成到 React 或 NextJS 项目中。Tailwind: 复用
本章通过将之前撸的按钮改成 NextJS 版,进而讨论 Tailwind 的复用原则。Tailwind: 配置和插件
本章将讨论如何配置 tailwind,以及几个 tailwind 官方插件。Tailwind: 制作响应式博客
本章我们使用 tailwind 将之前课程中 NextJS 迷你博客改造为响应式的布局。
React: SEO挑战、服务端渲染及本地存储
经过紧张的学习,React 课程终于暂告一个段落了。本章将是一个相对轻松的内容,我们一起探讨一下 React 应用的 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>
原因也很简单,我们是用 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!我要上报给官方,少说能拿个几万美刀!
一位不愿透露姓名的学员(毕竟要为几万美刀的安全负责)表示,他使用 Context 制作了用户登录,但按F5刷新网页之后,又变成未登录了。这是一个BUG,上报给官方少说能拿几万美刀——他肆意地遐想着。
同学,醒醒!你缺的不仅仅是美刀,更是缺少对基础知识的理解!
我们知道,我们开发的组件其实是作为虚拟DOM存在的,由 React 决定什么时候、以什么方式转换成真实 DOM 并渲染到页面上。虚拟 DOM 是保存在内存里的,所以每次刷新页面都会导致组件重走一次生命周期——就是说,每次刷新页面,你看到的其实是不同的实例。连组件都重新走一遍整个生命周期了,你觉得由它维护的 state
、props
不会丢失吗?
要避免这位同学遇到的问题,那就需要将那些数据进行持久化。
在后端,我们有很多种途径对数据进行持久化:写入到文件、保存到数据库等等。而在前端,我们可以利用 HTML 5 提供的 Storage
API实现。
有两种 Storage
:
localStorage
:本地存储sessionStorage
:会话存储
它们提供的 API 一样,只是存储数据的持续时间不同。会话存储基本上就是关闭浏览器,数据就会自动被清除;而本地存储则是,除非手动删除,否则它一直都在。
上面给出的文档链接里有示例代码,我们来看一下:
// 保存数据到 sessionStorage
sessionStorage.setItem('key', 'value');
// 从 sessionStorage 获取数据
let data = sessionStorage.getItem('key');
// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');
// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();
再说一遍,它们的API是一样的,把上面代码中的
sessionStorage
改成localStorage
就是本地存储
再说一遍,它们的API是一样的,把上面代码中的 sessionStorage
改成 localStorage
就是本地存储
本地存储的 React hook
定义一个 hook
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === "undefined") {
return initialValue;
}
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
使用 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 的学习,准备好了吗?