内容介绍
本专题假设你已经具备了基本的 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:类式组件、函数式组件及state和props
本章将讨论 React 的类式组件、函数式组件以及 React 两个最重要的属性:state
和 props
。
根据编写组件的风格不同,React 的组件可以分成:类式组件和函数式组件。
顾名思义,类式组件是指使用 ES6 的 class
语法,通过类的形式定义的组件;而函数式组件是指通过函数的形式定义的组件。在 React 18 之前,官方推荐的是类式组件;而 React 18 开始,官方推荐的是函数式组件。
除了在讨论一些原理性的知识(比如本章以后面章节的“生命周期”)时,本教程会使用类式组件,其它场景下均使用函数式组件。
无论你是通过 create-react-app
工具还是使用 vite 创建的脚手架,使用的都是函数式组件,让我们再来回顾一下:
import React from "react";
function App() {
return <h1>你好,AXUM中文网</h1>;
}
export default App;
你会看到,函数式组件非常简单:
- 定义一个函数,函数名通常就是组件名
- 函数的返回值是 JSX。它会在内存中作为 React 的虚拟DOM进行处理,并最终渲染到页面的真实DOM中
类式组件
下面,我们尝试把 App
组件改成使用类的形式来定义的类式组件:
import React from 'react';
class App extends React.Component {
render() {
return <h1>你好,axum.rs!</h1>;
}
}
export default App;
- 第3行:定义一个
App
类,它继承自React.Component
- 第4~6行:定义一个
render()
方法,它返回 JSX - 第9行:默认导出这个类
你可以查看和编辑源码。
通过上面的小例子,我们可以大胆地小结一下,对于类式组件:
- 类的名称就是组件名称
- 该类必须继承
React.Component
- 该类必须提供
render()
方法
render()是一个最重要的方法,它负责组件的最终渲染,在类式组件中,需要显式的定义 render()
方法,而在函数式组件中呢?——函数式组件本身就可以视为 render()
方法。函数式组件中,函数的返回值就可以视为render()
方法的返回值。
组件的状态:state
React 是状态驱动的页面的,也就是说可以根据不同状态来呈现不同UI。现在有个需求,要求把上例中的问候语改成动态内容。我们试着实现一下:
// 错误示范
import React from 'react';
class App extends React.Component {
name = 'axum.rs';
render() {
return <h1>你好,{this.name}!</h1>;
}
}
export default App;
这里我们在类中定义了一个 name
属性,并在 JSX 中访问它。运行一下发现貌似可以,其实不然:再跟我读一遍:React 是状态驱动的页面的。这个 name
是类的成员属性,并不是组件的状态。
在 React 有一个特殊的成员:state
,由它来维护组件的状态。
初始化 state
React.Component
定义了一个名为 state
的属性,既然我们的组件是继承自它,自然也有了 state
。state
默认值是 {}
,我们可以根据需要在自己的组件里给它初始化所需要的值:
class App extends React.Component {
// 初始化 state
state = {
name: 'axum.rs',
};
//...
}
访问 state
现在,我们可以访问 state
中的元素了(当然包括在 JSX 中访问):
class App extends React.Component {
// 初始化 state
state = {
name: 'axum.rs',
};
render() {
return <h1>你好,{this.state.name}!</h1>; // 访问state
}
}
请大声读三遍以下内容:
通过 setState
来改变状态,而不是直接修改!
// 错误:不要直接修改状态
this.state.name = 'AXUM中文网';
// 正确:通过 setState 来修改状态
this.setState({name:'AXUM中文网'});
setState
多种形式
setState
的参数有多种形式,你可以先通过官方文档来体验一下。这里我们先做简单的说明,在后续章节和实战部分会有真实案例。
setState(obj)
:这种方式的参数是一个 Javascript 的简单对象类型,比如上例的{name:'AXUM中文网'}
。这是最简单的方式,在这种方式下,如果name
不存在,则会新增到state
中,如果存在则更新它的值setState(currentState => returnNewStateFunction)
:这种方式的参数是一个函数,它的参数是当前的state
,它的返回值是新的state
。比如上例可以修改为:this.setState(currentState => ({name:'axum中文网'}));
。这种方式主要用于,新的状态依赖于当前状态。由于上例不存在这种需求,所以这种方式对于上例来说有点多余。
本节源码:axum-rs-react-class-state
组件的属性:props
这里说的属性可不是 OOP 中说的属性,给个 HTML/JSX 的例子给你看,你或许就知道了:
上面代码中的 id="title" width="50%" height="10rem"
就是组件的属性,在 React 使用特殊的 props
来维护。和 state
一样, 它们可以使用 Javascript 的简单对象来表示:
{
id: 'title',
width: '50%',
height: '10rem'
}
在类式组件中,通过构造函数来接收传递过来的 props
:
- 第4~6行:构造函数,通过
props
参数接收外部传递过来的属性 - 第8行:通过
this.props.name
读取传递过来的属性。由于继承React.Component
并通过super(props);
初始化了,所以作为子类的App
可以直接读取到this.props
在使用 App
组件时,就可以给它传递属性了:
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App name="axum.rs" />
</React.StrictMode>
);
- 第3行:使用
App
组件,并传递属性name
,它的值是axum.rs
本节代码在axum-rs-react-class-props
函数式组件的 props
我们先来看 props
。回顾一下类式组件是如何获取 props
的:通过构建函数的参数。让我们简化一下:通过函数的参数!是的,由于 props
是通过函数的参数传递的,所以能适用于类组件的构建函数里,自然也适用于函数式组件。
import React from 'react';
function App(props) {
return <h1>你好,{props.name}</h1>;
}
export default App;
现在我们把 App
组件改回为函数式组件,并新加一个 props
形参,这样它就可以接收外部传递过来的属性了,并且可以在包括 JSX 在内的代码中访问它。
同样,在使用 App
组件时,我们向它传递属性:
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App name="axum.rs" />
</React.StrictMode>
);
hooks:让函数式组件拥有 state
为了让函数式组件能使用 state
,React 提供了名为useState
的 hook。
- 引入
useState
:import { useState } from 'react'
- 使用
useState
:const [name, setName] = useState('axum.rs')
useState
是一个函数,它:
- 返回一个数组,数组的成员分别是:绑定到该状态的变量名(比如上面的
name
变量)以及更新该状态的函数名(比如上面的setName
) - 接收一个参数,该参数用于设置状态的初始化(比如上面的
axum.rs
)
import React, { useState } from 'react';
function App() {
// 初始化 state
const [name, setName] = useState('axum.rs');
// 更新state
// setName('AXUM中文网');
return <h1>你好,{name}</h1>; // 读取state
}
export default App;
本节代码在:axum-rs-react-fn-state