前言
家人们,咱就是说,React 这玩意儿就纯纯一个 "互联网打工人" ,几年不更新,直接从 "穿西装打领带的老派白领"(类组件) ,进化成了 "穿卫衣踩拖鞋的高效新青年"(函数组件 + hooks) 。但不得不说是真好用!看完你就知道这波 "改头换面" 到底有多爽。
一、React 16.8 前:类组件的 "老派职场生存法则"
在 hooks 还没出生的年代,写 React 组件那叫一个 "仪式感拉满" ------ 必须套个class,像入职要填一堆表格似的。总之一个字--"装"!
1. 状态,得用this.state"供着"?
想存个变量还能让组件 "动起来"?得搁constructor里写this.state = {},仿佛给变量办了张 "职场工牌" ,只有挂上这牌,修改它才能触发 "全组开会"(组件重新渲染)。
比如:
jsx
export default class App extends Component {
constructor() {
super();
this.state = {
count: 0
} // 给count发工牌:"你是咱组的状态人了!"
}
add() {
this.setState({
count: this.state.count + 1
}) // 修改状态="给工牌升级",触发渲染
}
render() {
console.log('render'); // 一修改就"开会"
return <button onClick={this.add.bind(this)}>{this.state.count}</button>
}
}
点击前:

点击3次后:

这bind(this)更是 "老派痛点" ------ 不用它,this能给你跑到 "外星",主打一个 "我认识你,但你不认识我" 的尴尬。
2. 生命周期:像职场的 "上下班打卡 + 加班预警"
类组件的生命周期,那就是 "打工人的一天":
componentDidMount:组件 "入职第一天",刚渲染完就触发,适合干 "刚入职先装个软件"(比如发请求);componentDidUpdate:组件 "每次改需求",状态变了就触发,相当于 "改完方案得同步给全组";componentWillUnmount:组件 "离职前",销毁前触发,用来 "删软件清数据"(比如清定时器)。
依旧代码:
jsx
import React, { Component } from 'react';
export default class App3 extends Component {
constructor(props) {
super(props);
// 初始化状态:模拟"入职时的工作清单"和"待办数量"
this.state = {
workList: [], // 工作清单
todoCount: 0 // 待办数量
};
// 模拟一个"上班期间的定时提醒"
this.timer = null;
}
// 1. componentDidMount:组件"入职第一天"
// 刚渲染完成(办完入职手续)就触发,只执行一次!
// 适合做"入职首件事":比如对接接口拿数据、初始化定时器、绑定事件
componentDidMount() {
console.log('✨ 组件入职报到!');
// 模拟"入职先拉取工作清单"(发请求)
fetch('https://mock-api.com/work/list')
.then(res => res.json())
.then(data => {
this.setState({
workList: data.list,
todoCount: data.list.length
});
});
// 模拟"入职后设置定时提醒"(比如每小时检查待办)
this.timer = setInterval(() => {
console.log('⏰ 定时检查:当前待办数 →', this.state.todoCount);
}, 3600000);
}
// 2. componentDidUpdate:组件"每次改需求"
// 状态/属性变化后(改了工作方案)触发,每次更新都会执行!
// 适合做"需求变更后的同步操作":比如待办数变了,同步更新统计
componentDidUpdate(prevProps, prevState) {
// 注意!一定要加判断,否则会无限循环(改状态→触发更新→又改状态→再更新)
if (prevState.todoCount !== this.state.todoCount) {
console.log('📝 需求变更!待办数从', prevState.todoCount, '变成', this.state.todoCount);
// 模拟"待办数变了,同步到公司看板"
console.log('🔄 已同步待办数到公司看板~');
}
}
// 3. componentWillUnmount:组件"离职前"
// 组件销毁(离职)前触发,只执行一次!
// 适合做"离职收尾工作":清定时器、解绑事件、取消请求,避免内存泄漏
componentWillUnmount() {
console.log('👋 组件准备离职!');
// 清除定时提醒(带走自己的东西,不占公司资源)
clearInterval(this.timer);
// 模拟"取消未完成的请求"(避免离职后还发请求打扰公司)
this.cancelRequest && this.cancelRequest();
console.log('✅ 收尾工作完成,可安心离职~');
}
// 模拟"新增待办"(触发状态更新,进而触发componentDidUpdate)
addTodo = () => {
this.setState(prevState => ({
todoCount: prevState.todoCount + 1
}));
};
render() {
const { workList, todoCount } = this.state;
return (
<div className="work-container">
<h3>打工人的工作面板</h3>
<p>当前待办数:{todoCount}</p>
<button onClick={this.addTodo}>新增待办(改需求)</button>
<ul>
{workList.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
}
拆解:
1.componentDidMount(入职报到) :组件第一次渲染到页面后,这个方法就像你第一天入职 ------ 办完手续坐在工位上,第一件事肯定是 "对接工作"(发请求拿数据) 、"配置工作环境"(设定时器)。它只执行一次,不会因为后续改需求重复触发,完美契合 "入职首件事" 的场景。如果在这里忘了设定时器 / 绑事件,后续想补就只能塞到其他地方,容易乱。
2.componentDidUpdate(需求变更) :每次调用setState修改状态(比如点击 "新增待办"),组件重新渲染后就会触发这个方法,像极了公司改需求:你改完方案后,得同步给产品、测试、后端(对应代码里 "同步待办数到看板")。但一定要加prevState/prevProps的判断!不然每次更新都改状态,会陷入 "改需求→同步→又改需求→又同步" 的无限循环,就像打工人改需求改到崩溃。
3.componentWillUnmount(离职收尾) :当组件从页面消失(比如路由跳转、关闭弹窗),这个方法就是 "离职前的最后 10 分钟"------ 必须把自己的东西清干净:定时提醒要关(不然离职后还在公司弹窗)、未完成的请求要取消(不然给公司造垃圾数据)、绑定的事件要解绑(不然可能导致内存泄漏)。要是忘了清定时器,就像离职后还占着公司的工位,看似小事,多了会拖垮整个项目(性能下降)。
老派生命周期的 "槽点":
这么写看似逻辑清晰,但实际开发中,一个组件的 "数据请求 + 定时器 + 事件绑定" 可能分散在三个生命周期里 ------ 比如 "发请求" 在componentDidMount,"请求结果更新后同步数据" 在componentDidUpdate,"取消请求" 在componentWillUnmount。原本相关的逻辑被拆得七零八落,就像你把 "对接一个需求" 的动作,拆到 "入职、改需求、离职" 三个阶段,后期维护时要翻遍整个文件找逻辑,主打一个 "找得到开头,找不到结尾"。
这个真的挺难搞懂的,我刚接触的时候差点劝退。
二、React 17+:hooks 来了!函数组件直接 "躺赢"
hooks 一上线,直接把函数组件从 "边缘外包岗" 抬成了 "核心业务岗"------ 不用class,不用this,写代码像 "唠嗑" 一样轻松。
1. useState:状态?"随手揣兜里" 就行
想存个能触发渲染的变量?useState一句话搞定,不用constructor,不用this,主打一个 "轻装上阵"。
直接拿我第一个举的例子:
jsx
import { useState } from 'react'
export default function App() {
const count = 0;
function add() {
count += 1;
}
return <button onClick={add}>{count}</button>
}
如果你这样写的话根本没用,违背了 React 函数组件的状态管理规则 。无论你按多少次按钮结果都是0:

为啥凭啥?原因如下:
- 当点击按钮执行
add函数时,count += 1只是在当前函数执行栈里修改了变量值,但这个修改不会通知 React "组件需要重新渲染"; - 函数组件每次渲染都是一次独立的函数执行,即便本次执行里
count变了,React 没感知到,就不会重新调用App函数,页面上显示的依然是初始渲染时的0。
这时候就得请出useState方法了:
jsx
import { useState } from 'react'
export default function App() {
const [count, setCount] = useState(0); // 一句话:"count是状态,setCount是修改它的按钮"
const [list, setList] = useState([]); // 还能一次性搞多个状态,不用裹在 this.state里!
function add() {
setCount(count + 1); // 改状态="按按钮",直接触发渲染,没this的事儿!
}
return <button onClick={add}>{count}</button>
}
点击前:

点击3次后:

这样我们就成功修改了count的值。
2. useEffect:生命周期?"一个函数承包所有活"
类组件的三个生命周期,hooks 用一个useEffect就给 "合并裁员" 了,还能 "按需上班" ,主打一个 "精准摸鱼"。
jsx
import { useEffect, useState } from "react";
export default function App2() {
const [list, setList] = useState([]);
// 场景1:只在"入职时"发请求 → 第二个参数传空数组[]
useEffect(() => {
fetch('https://mock.mengxuegu.com/mock/66585c4db462b81cb3916d3e/songer/songer') // 刚入职先拉数据
.then(res => res.json())
.then(data => setList([...list, ...data.data]))
}, []) // 空数组="只上一天班,之后躺平"
// 场景2:count变了才触发 → 第二个参数传[count]
useEffect(() => {
console.log('count变了,我才干活');
}, [count]) // count是"考勤机",它变了才打卡
// 场景3:离职前清东西 → return一个函数
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer); // 离职前把定时器"关了再走"
}, [])
}

"时间管理大师" --useEffect:
- 第二个参数传
[]:"我只在组件第一次渲染后干一次活,多一次都不干"; - 传
[x]:"只有 x 变了,我才动一动"; - 返回函数:"走之前把烂摊子收拾干净"。直接把类组件的三个生命周期按在地上摩擦,效率拉满!
三、总结:从 "老派" 到 "新派",到底爽在哪?
| 对比项 | 类组件(16.8 前) | 函数组件 + hooks(17+) |
|---|---|---|
| 代码量 | 要写 class、constructor、bind | 直接 function,一行 useState 搞定 |
| 状态管理 | 裹在 this.state 里,this 易迷路 | 变量 + 修改函数分离,清爽不绕弯 |
| 生命周期 | 多个函数分散写,易冗余 | 一个 useEffect 按需配置,逻辑聚合 |
| 复用性 | 得写 HOC/Render Props(麻烦) | 自定义 hooks 直接 "复制粘贴逻辑" |
咱就是说,现在写 React 不用 hooks ,就像 "快 2026 了还在用按键手机"------ 不是不能用,但就是 "别人都在刷短视频,你在那按数字键发短信",主打一个 "慢半拍的倔强"。
结语
说到底,React 从类组件 到 hooks 的进化,就像把 "做饭得先砌灶台" 改成了 "点外卖还能选定制配料" ------ 少了繁琐的仪式感,多了精准的掌控力。如今的 hooks 早已是 React 的 "当家花旦",但咱也不用嫌弃类组件 "老古董",毕竟它是 hooks 的 "前辈恩师"。总之,不管是老派还是新派,能高效写好组件的,都是咱前端圈的 "好派"。
这篇文章里面的知识真的难,码了很久有了这篇文章,但还不是很透彻。如果有分析的不对的地方,麻烦大佬指出😭