知蛛网
  • 首页
  • 会员
  • 活动
  • 工作台

常见问题
活动
关于我们
联系我们
隐私协议
用户协议
会员协议
© 2026 知蛛网. 保留所有权利。
首页会员工作台我的
flynn@flynn
主页wiki简历作品集
目录
全部书籍
00-路线
  • 学习路线
  • 命名与写作规范
01-计算机基础
01-计算机网络
  • 互联网是如何工作的
  • HTTP协议
  • TCP/IP协议
  • 浏览器直接打开本地html文件,请求时的协议问题
02-浏览器原理
  • 浏览器是如何渲染页面的
  • 浏览器是如何渲染页面的
  • 面试之浏览器
03-操作系统
  • 进程与线程
  • 内存管理与虚拟内存
  • IO 模型与多路复用
  • 文件系统与页缓存
04-数据结构与算法
  • 数组与链表
  • 栈与队列
  • 哈希表
  • 树与堆
  • 基础数据结构
01-基础数据结构
02-高级算法
  • 排序算法
  • 二分查找
  • 递归与回溯
  • 动态规划
  • 双指针与滑动窗口
03-leetcode刷题
02-前端核心
01-web开发
  • Web 和 Web 标准
  • web 入门
  • web 开发
  • URL
  • 域名
  • Web服务器
  • 命令行
  • 工作流程和流程
  • 超链接
  • 浏览器指纹
02-html
  • HTML基础语法
  • HTML 概述
  • HTML 发展史
  • HTML调试
  • HTML标题与段落
  • 文本格式化
  • 强调与重要性
  • 块级元素和内联元素
  • 列表
  • 区块
  • 语义元素
  • 页面结构化和语义化
  • 超链接
  • 相对路径和绝对路径
  • 图片
  • 表格
  • 表单和按钮
  • 多媒体
  • 视频/音频
  • HTML 头部
  • HTML 字符集
  • HTML颜色
  • HTML 语言代码
  • HTML 国家/地区
  • Emoji (表情符号)
  • HTML 标签简写及全称 |
  • SVG
  • Canvas 2D
  • Canvas 3D
  • 框架 `<iframe>`
  • HTML 拖放
  • HTML5 Geolocation(地理定位)
  • Web 存储
  • HTML URL 编码
  • MathML
  • 远程图片资源在自己网站中无法展示问题
03-css
  • CSS简介
  • CSS 语法
  • CSS 创建
  • CSS 发展史
  • CSS 浏览器支持
  • CSS 选择器
  • CSS `!important` 规则
  • css颜色
  • CSS 文本格式
  • CSS 盒子模型
  • CSS 尺寸
  • CSS 内边距
  • CSS 外边距
  • CSS 边框
  • CSS 轮廓
  • CSS 背景(background)
  • CSS 溢出
  • CSS 文档流
  • CSS 显示和可见性
  • CSS 浮动
  • CSS 定位
  • CSS 对齐方式
  • CSS 网页布局
  • CSS 多列布局(CSS Multi-column Layout)
  • CSS 透明度
  • CSS 响应式设计(Responsive Design)
  • CSS 媒体查询
  • CSS 列表
  • CSS 表格
  • CSS 表单
  • CSS 链接
  • CSS 用户界面
  • CSS 计数器
  • CSS 过渡
  • CSS 动画
  • CSS 2D 转换
  • CSS 3D 转换
  • CSS 变量(CSS Custom Properties)
  • CSS 原生嵌套(CSS Nesting)
  • CSS 函数(CSS Functions)
04-javascript
  • 什么是 JavaScript?
  • 编程范式(Programming Paradigm)
  • 什么是范式?
  • ECMAScript 规范
  • 什么是语法糖
  • 开发环境搭建
  • 什么是堆和栈?
  • 什么是执行上下文
  • JavaScript 垃圾回收机制
  • 作业队列与事件循环
  • 深拷贝和浅拷贝
  • 语法与类型
  • 字面量
  • 控制流与错误处理
  • 循环与迭代
  • 函数
  • 表达式与运算符
  • 数字和字符串
  • 表达日期与时间
  • 正则表达式
  • 索引集合类
  • 带键的集合
  • 对象
  • 类
  • Promise
  • async/await
  • 迭代器和生成器
  • 国际化
  • 模块
  • 资源管理
  • 属性的可枚举性和所有权
  • 闭包
  • 继承与原型链
  • 元编程
  • 内存管理
  • 内置对象
  • arguments 对象
  • BOM 对象(浏览器对象模型)
  • DOM 对象(文档对象模型)
  • bind、apply、call的区别
  • new 操作符
  • typeof 和 instanceof 的区别
  • HTML5 Web Workers
05-typescript
  • TypeScript 类型系统基础
  • 类型体操
03-框架与跨端
01-react
  • 开发环境搭建
  • JSX
  • 组件
  • 生命周期
  • Hooks
  • 组件通信
  • 状态管理
  • React 19 新特性
  • useCallback 闭包陷阱
  • 常用的性能优化操作
  • Firbe 架构
  • React 18 新特性
  • useRef
  • 基于umijs 4.0 搭建官网
  • react+vite本地开发,如何手机联调
  • React 实现谷歌登录
  • React 项目调起 WhatsApp
02-vue
  • vue 解决跨域请求
  • 在vue2使用TinyMCE富文本编辑器
  • 使用jszip 导出新闻
  • Vue 本地开发启用 https
  • 基于vue3+vite+ts+elementplus+pinia+axios搭建后台管理系统
03-react-native
  • iOS 开发环境(RN 0.72)
  • RN 原生模块(Native Module)
  • 查看Maven包的Java包名
  • 优化 APP 启动速度
  • 安全键盘
  • 启动图与 Icon 尺寸规范
  • RN如何生成/配置iOS的开发者证书和生产证书
  • 邓白氏编码
  • 微信开放平台配置Universal Link
  • 上架至Apple App Store
04-android
  • 开发环境搭建
  • Android项目目录结构
  • 认识Gradle
04-工程化
01-git
  • 如何解决已被git跟踪文件不在跟踪
  • git标签
  • Git报错: Failed to connect to github.com port 443 解决方案
  • Git 分支操作速查
02-构建工具
  • 构建工具原理与选型
02-webpack
  • webpack 核心概念与构建流程
  • webpack 性能优化
03-vite
  • vite 为什么快
  • vite 插件与生产构建
03-测试
  • 前端测试体系
04-部署
  • Nginx 反向代理解决跨域
  • SPA 刷新非首页报 404
05-docker
  • Docker 常用命令
  • docker-compose nginx配置ssl证书
  • Docker Desktop 升级后 docker-compose 命令找不到
06-性能优化
  • 前端性能优化体系
  • 背景 GIF 优化方案
07-微前端
  • 微前端实战(qiankun)
  • 微前端 · qiankun
01-qiankun
05-后端与数据
01-nodejs
  • Node 版本与依赖的 engines 冲突
  • Express 实现 Gmail 发信(邮箱验证码)
02-php
  • 浏览器保存新闻,发布到自有网站
  • [分布式] 浏览器保存新闻,发布到自有网站
  • 邮件发送,多账号轮询
  • nginx和php-fpm通信问题导致网站页面空白
03-python
  • macOS M1 芯片 如何安装 py 和 tkinter
  • tkinter 编写的程序如何打包成桌面软件
04-架构设计
  • 后台管理系统中角色管理、管理员管理、权限设置他们三者之间的关系
05-运维
  • redis启动失败
  • 实现自动备份宝塔项目及数据库到本地
  • 宝塔面板
01-宝塔
06-实战项目
  • 实战准备工作
02-项目记录
  • AI-Chat 模块技术文档
  • CRMChat 部署
07-面试专项
01-面试
  • 面试之自我介绍
  • CSS 面试
  • JS面试
  • React面试
  • Vue面试
  • RN 面试 · 题目清单
  • RN 面试 · 答案详解
  • RN 物流公司 · 题目清单
  • RN 物流公司 · 答案详解
  • Uniapp 面试
  • 带团队经验
12-react专项
  • 一个表格,某一行的某一列数据变动了,如何优化性能?
13-reactnative专项
  • RN 开发过程中,有遇到什么棘手的问题?你是如何解决的?
14-过往面试总结
  • 冷哥传媒 · 面试题
  • 沐腾科技 · 面试题
  • 字符频率排序
02-面试八股
  • 网络八股
  • 浏览器八股
  • 工程化八股
03-算法面试题
  • 前端高频手写题
  • 场景设计题
04-真实面试经历
  • 20251027 盾蓝科技 面试
  • 20251028 芝麻甜心 面试
08-工具
01-n8n
  • 初始n8n
  • 快速入门
  • 在宝塔中搭建n8n环境
  • n8n中常用节点
  • n8n和代码的区别
02-Trae
  • Figma MCP 配置指南
03-UI_UX_pro_max
  • UI_UX_pro_max的使用
04-开发环境
  • VMWare虚拟机安装
  • PowerShell 执行策略与编码设置
98-杂项
  • A股股票交易相关费用
99-手册
  • iOS 开发者账号申请流程及费用
  • 邓白氏编码申请及费用
  • App 推送通道申请及费用
  • App 开发收费项目清单
  • 注册AWS账号
  • 使用Amazon Polly实现文本转语音
  • Google 翻译 Key 申请与前端调用
  • 使用SmsForwarder转发短信

生命周期

01-react2026/11/14

生命周期概览

类组件生命周期三个阶段:

  • 挂载阶段(Mounting)
  • 更新阶段(Updating)
  • 卸载阶段(Unmounting)

生命周期图示

挂载阶段:
constructor → getDerivedStateFromProps → render → componentDidMount

更新阶段:
getDerivedStateFromProps → shouldComponentUpdate → render →
getSnapshotBeforeUpdate → componentDidUpdate

卸载阶段:
componentWillUnmount

错误处理:
getDerivedStateFromError → componentDidCatch

挂载阶段(Mounting)

constructor()

组件实例化时调用,用于初始化 state 和绑定方法。

class MyComponent extends React.Component {
    constructor(props) {
        super(props); // 必须调用 super(props)

        // 初始化 state
        this.state = {
            count: 0,
            data: null,
        };

        // 绑定事件处理方法
        this.handleClick = this.handleClick.bind(this);
        this.handleChange = this.handleChange.bind(this);

        console.log("constructor 被调用");
    }

    handleClick() {
        // 处理点击
    }

    handleChange() {
        // 处理变化
    }

    render() {
        return <div>组件内容</div>;
    }
}

static getDerivedStateFromProps()

在组件实例化或接收新 props 时调用,返回一个对象来更新 state,或返回 null 不更新。

class MyComponent extends React.Component {
    state = {
        derivedValue: "",
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        console.log("getDerivedStateFromProps 被调用");
        console.log("新的 props:", nextProps);
        console.log("当前的 state:", prevState);

        // 根据 props 计算派生 state
        if (nextProps.value !== prevState.lastValue) {
            return {
                derivedValue: nextProps.value.toUpperCase(),
                lastValue: nextProps.value,
            };
        }

        return null; // 不更新 state
    }

    render() {
        return <div>派生值: {this.state.derivedValue}</div>;
    }
}

render()

必须实现的方法,返回 JSX。

class MyComponent extends React.Component {
    render() {
        console.log("render 被调用");

        // 不能在这里调用 setState()
        // 应该是一个纯函数

        return (
            <div>
                <h1>标题</h1>
                <p>计数: {this.state.count}</p>
                <button onClick={this.handleClick}>点击</button>
            </div>
        );
    }
}

componentDidMount()

组件挂载到 DOM 后立即调用,适合执行副作用操作。

class MyComponent extends React.Component {
    state = {
        data: null,
        loading: true,
        error: null,
    };

    async componentDidMount() {
        console.log("componentDidMount 被调用");

        try {
            // 1. 发起网络请求
            const response = await fetch("https://api.example.com/data");
            const data = await response.json();

            this.setState({
                data,
                loading: false,
            });

            // 2. 设置定时器
            this.timerId = setInterval(() => {
                console.log("定时器执行");
            }, 1000);

            // 3. 添加事件监听器
            window.addEventListener("resize", this.handleResize);

            // 4. 操作 DOM
            this.containerRef.current.focus();

            // 5. 初始化第三方库
            this.chart = new Chart(this.canvasRef.current, config);
        } catch (error) {
            this.setState({
                error: error.message,
                loading: false,
            });
        }
    }

    handleResize = () => {
        console.log("窗口大小改变");
    };

    render() {
        // render 方法
    }
}
上一篇组件
下一篇Hooks
本页目录
生命周期概览生命周期图示挂载阶段(Mounting)constructor()static getDerivedStateFromProps()render()componentDidMount()更新阶段(Updating)static getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()卸载阶段(Unmounting)componentWillUnmount()错误处理生命周期static getDerivedStateFromError()componentDidCatch()已废弃的生命周期方法componentWillMount()componentWillReceiveProps()componentWillUpdate()函数组件的生命周期(Hooks 替代)使用 useEffect 模拟生命周期自定义 Hook 封装生命周期逻辑生命周期最佳实践网络请求性能优化动画和第三方库集成常见生命周期误区生命周期执行顺序示例总结React 生命周期提供了组件在不同阶段的控制点:现代 React 开发建议:

更新阶段(Updating)

static getDerivedStateFromProps()

在更新阶段也会调用(同挂载阶段)。

shouldComponentUpdate()

决定组件是否需要重新渲染,返回布尔值。

class MyComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        console.log("shouldComponentUpdate 被调用");

        // 性能优化:只有当特定 props 或 state 改变时才重新渲染
        if (this.props.id !== nextProps.id) {
            return true;
        }

        if (this.state.count !== nextState.count) {
            return true;
        }

        // 其他情况不重新渲染
        return false;

        // 或者使用浅比较
        // return !shallowEqual(this.props, nextProps) ||
        //        !shallowEqual(this.state, nextState);
    }

    render() {
        return <div>组件内容</div>;
    }
}

// React.PureComponent 自动实现了浅比较的 shouldComponentUpdate
class PureComponentExample extends React.PureComponent {
    // 自动比较 props 和 state 的变化
    render() {
        return <div>PureComponent</div>;
    }
}

render()

重新渲染组件。

getSnapshotBeforeUpdate()

在 DOM 更新前获取快照,返回值会作为 componentDidUpdate 的第三个参数。

class ScrollList extends React.Component {
    state = {
        items: [],
    };

    listRef = React.createRef();

    getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log("getSnapshotBeforeUpdate 被调用");

        // 获取滚动位置
        const list = this.listRef.current;
        if (prevState.items.length < this.state.items.length) {
            // 新项目添加到列表顶部,记录当前滚动位置
            return list.scrollHeight - list.scrollTop;
        }

        return null;
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("componentDidUpdate 被调用,快照:", snapshot);

        if (snapshot !== null) {
            const list = this.listRef.current;
            // 保持滚动位置
            list.scrollTop = list.scrollHeight - snapshot;
        }
    }

    addItem = () => {
        this.setState(prevState => ({
            items: [`新项目 ${Date.now()}`, ...prevState.items],
        }));
    };

    render() {
        return (
            <div>
                <button onClick={this.addItem}>添加项目</button>
                <div ref={this.listRef} style={{ height: "200px", overflow: "auto" }}>
                    {this.state.items.map((item, index) => (
                        <div
                            key={index}
                            style={{ padding: "10px", borderBottom: "1px solid #ccc" }}
                        >
                            {item}
                        </div>
                    ))}
                </div>
            </div>
        );
    }
}

componentDidUpdate()

组件更新后立即调用,适合执行 DOM 操作或网络请求。

class MyComponent extends React.Component {
    state = {
        userData: null,
    };

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("componentDidUpdate 被调用");

        // 比较 props 变化
        if (this.props.userId !== prevProps.userId) {
            // 用户ID改变,重新获取数据
            this.fetchUserData(this.props.userId);
        }

        // 比较 state 变化
        if (this.state.searchQuery !== prevState.searchQuery) {
            // 搜索条件改变,重新搜索
            this.performSearch(this.state.searchQuery);
        }

        // 使用快照
        if (snapshot) {
            console.log("从 getSnapshotBeforeUpdate 获取的快照:", snapshot);
        }

        // 更新第三方库
        if (this.chart && this.props.data !== prevProps.data) {
            this.chart.update(this.props.data);
        }

        // 发送分析数据
        if (this.state.pageViewCount !== prevState.pageViewCount) {
            analytics.track("page_view", { count: this.state.pageViewCount });
        }
    }

    fetchUserData = async userId => {
        const response = await fetch(`/api/users/${userId}`);
        const data = await response.json();
        this.setState({ userData: data });
    };

    render() {
        // render 方法
    }
}

卸载阶段(Unmounting)

componentWillUnmount()

组件卸载前调用,用于清理操作。

class MyComponent extends React.Component {
    state = {
        timerId: null,
        subscription: null,
        connection: null,
    };

    async componentDidMount() {
        // 1. 设置定时器
        const timerId = setInterval(() => {
            console.log("定时执行");
        }, 1000);
        this.setState({ timerId });

        // 2. 订阅事件
        const subscription = eventBus.subscribe("dataUpdate", this.handleDataUpdate);
        this.setState({ subscription });

        // 3. 建立 WebSocket 连接
        const connection = new WebSocket("ws://example.com");
        connection.onmessage = this.handleMessage;
        this.setState({ connection });

        // 4. 添加事件监听器
        window.addEventListener("resize", this.handleResize);

        // 5. 初始化第三方库
        this.map = new Map(this.mapContainer.current, options);
    }

    componentWillUnmount() {
        console.log("componentWillUnmount 被调用");

        // 1. 清除定时器
        if (this.state.timerId) {
            clearInterval(this.state.timerId);
        }

        // 2. 取消订阅
        if (this.state.subscription) {
            this.state.subscription.unsubscribe();
        }

        // 3. 关闭连接
        if (this.state.connection) {
            this.state.connection.close();
        }

        // 4. 移除事件监听器
        window.removeEventListener("resize", this.handleResize);

        // 5. 清理第三方库
        if (this.map) {
            this.map.destroy();
        }

        // 6. 取消未完成的网络请求
        if (this.controller) {
            this.controller.abort();
        }

        // 7. 清理 refs
        this.containerRef = null;

        // 8. 重置状态(虽然 React 会处理,但某些情况下可能需要)
        this.setState = () => {};
    }

    handleResize = () => {
        // 处理窗口大小改变
    };

    render() {
        return <div ref={this.mapContainer} />;
    }
}

错误处理生命周期

static getDerivedStateFromError()

在子组件抛出错误后调用,用于渲染降级 UI。

class ErrorBoundary extends React.Component {
    state = {
        hasError: false,
        error: null,
        errorInfo: null,
    };

    static getDerivedStateFromError(error) {
        console.log("getDerivedStateFromError 被调用");

        // 更新 state 以显示降级 UI
        return {
            hasError: true,
            error: error,
        };
    }

    componentDidCatch(error, errorInfo) {
        console.log("componentDidCatch 被调用");

        // 可以在这里记录错误信息
        console.error("错误:", error);
        console.error("错误信息:", errorInfo);

        // 发送错误到监控服务
        logErrorToService(error, errorInfo);

        this.setState({
            errorInfo: errorInfo,
        });
    }

    resetError = () => {
        this.setState({
            hasError: false,
            error: null,
            errorInfo: null,
        });
    };

    render() {
        if (this.state.hasError) {
            // 降级 UI
            return (
                <div className="error-boundary">
                    <h2>出错了!</h2>
                    <p>{this.state.error && this.state.error.toString()}</p>
                    <details style={{ whiteSpace: "pre-wrap" }}>
                        {this.state.errorInfo && this.state.errorInfo.componentStack}
                    </details>
                    <button onClick={this.resetError}>重试</button>
                </div>
            );
        }

        // 正常渲染子组件
        return this.props.children;
    }
}

// 使用方式
function App() {
    return (
        <ErrorBoundary>
            <BuggyComponent />
        </ErrorBoundary>
    );
}

componentDidCatch()

在子组件抛出错误后调用,用于记录错误信息。

已废弃的生命周期方法

componentWillMount()

// ❌ 已废弃
componentWillMount() {
  console.log('componentWillMount - 已废弃');
  // 不推荐在这里发起网络请求
}

// ✅ 替代方案:使用 constructor 或 componentDidMount
constructor(props) {
  super(props);
  // 初始化工作
}

componentDidMount() {
  // 发起网络请求
}

componentWillReceiveProps()

// ❌ 已废弃
componentWillReceiveProps(nextProps) {
  if (this.props.userId !== nextProps.userId) {
    this.fetchData(nextProps.userId);
  }
}

// ✅ 替代方案:使用 getDerivedStateFromProps 或 componentDidUpdate
static getDerivedStateFromProps(nextProps, prevState) {
  // 派生 state
}

componentDidUpdate(prevProps) {
  if (this.props.userId !== prevProps.userId) {
    this.fetchData(this.props.userId);
  }
}

componentWillUpdate()

// ❌ 已废弃
componentWillUpdate(nextProps, nextState) {
  // 准备更新
}

// ✅ 替代方案:使用 getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState) {
  // 获取 DOM 更新前的快照
}

函数组件的生命周期(Hooks 替代)

使用 useEffect 模拟生命周期

import { useState, useEffect, useRef } from "react";

function FunctionComponentLifecycle(props) {
    const [count, setCount] = useState(0);
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    const prevCountRef = useRef();
    const prevPropsRef = useRef(props);

    // 模拟 constructor
    const initialState = () => {
        console.log("模拟 constructor - 只执行一次");
        return 0;
    };

    const [stateValue, setStateValue] = useState(() => initialState());

    // 模拟 componentDidMount
    useEffect(() => {
        console.log("模拟 componentDidMount - 只执行一次");

        // 发起网络请求
        fetchData();

        // 设置定时器
        const timerId = setInterval(() => {
            console.log("定时器执行");
        }, 1000);

        // 添加事件监听器
        window.addEventListener("resize", handleResize);

        // 清理函数 - 模拟 componentWillUnmount
        return () => {
            console.log("模拟 componentWillUnmount");
            clearInterval(timerId);
            window.removeEventListener("resize", handleResize);
        };
    }, []); // 空依赖数组表示只运行一次

    // 模拟 componentDidUpdate(特定 state/props 变化时)
    useEffect(() => {
        console.log("模拟 componentDidUpdate - count 变化:", count);

        // 可以执行副作用操作
        document.title = `计数: ${count}`;

        // 发送分析数据
        if (prevCountRef.current !== undefined) {
            console.log(`计数从 ${prevCountRef.current} 变为 ${count}`);
        }

        // 更新 ref
        prevCountRef.current = count;
    }, [count]); // 依赖 count,count 变化时执行

    // 模拟 getDerivedStateFromProps
    useEffect(() => {
        if (prevPropsRef.current.userId !== props.userId) {
            console.log("props.userId 变化,重新获取数据");
            fetchUserData(props.userId);
        }

        prevPropsRef.current = props;
    }, [props.userId]);

    // 模拟 getSnapshotBeforeUpdate + componentDidUpdate
    const prevCount = useRef(count);
    useEffect(() => {
        // 在渲染后执行,类似于 componentDidUpdate
        console.log(`计数更新: ${prevCount.current} -> ${count}`);

        if (prevCount.current !== count) {
            // 这里可以访问到更新后的 DOM
            console.log("DOM 已更新");
        }

        prevCount.current = count;
    });

    // 获取数据函数
    const fetchData = async () => {
        try {
            setLoading(true);
            const response = await fetch("https://api.example.com/data");
            const result = await response.json();
            setData(result);
        } catch (error) {
            console.error("获取数据失败:", error);
        } finally {
            setLoading(false);
        }
    };

    const fetchUserData = async userId => {
        // 获取用户数据
    };

    const handleResize = () => {
        console.log("窗口大小改变");
    };

    const handleClick = () => {
        setCount(count + 1);
    };

    // 模拟 render
    console.log("模拟 render - 每次更新都执行");

    if (loading) {
        return <div>加载中...</div>;
    }

    return (
        <div>
            <h1>函数组件生命周期示例</h1>
            <p>计数: {count}</p>
            <button onClick={handleClick}>增加</button>
            <p>数据: {JSON.stringify(data)}</p>
        </div>
    );
}

自定义 Hook 封装生命周期逻辑

import { useEffect, useRef } from "react";

// 自定义 Hook:模拟 componentDidMount
function useDidMount(callback) {
    useEffect(() => {
        callback();
    }, []); // 空数组确保只执行一次
}

// 自定义 Hook:模拟 componentDidUpdate
function useDidUpdate(callback, dependencies) {
    const hasMounted = useRef(false);

    useEffect(() => {
        if (hasMounted.current) {
            callback();
        } else {
            hasMounted.current = true;
        }
    }, dependencies);
}

// 自定义 Hook:模拟 componentWillUnmount
function useWillUnmount(callback) {
    useEffect(() => {
        return callback;
    }, []);
}

// 使用示例
function ComponentWithCustomHooks() {
    useDidMount(() => {
        console.log("组件已挂载");
    });

    useDidUpdate(() => {
        console.log("组件已更新");
    }, []); // 依赖项

    useWillUnmount(() => {
        console.log("组件即将卸载");
    });

    return <div>组件内容</div>;
}

生命周期最佳实践

网络请求

class DataFetcher extends React.Component {
    state = {
        data: null,
        loading: true,
        error: null,
    };

    controller = new AbortController(); // 用于取消请求

    async componentDidMount() {
        await this.fetchData();
    }

    async componentDidUpdate(prevProps) {
        if (this.props.query !== prevProps.query) {
            // 取消之前的请求
            this.controller.abort();
            this.controller = new AbortController();

            await this.fetchData();
        }
    }

    componentWillUnmount() {
        // 组件卸载时取消请求
        this.controller.abort();
    }

    async fetchData() {
        try {
            this.setState({ loading: true, error: null });

            const response = await fetch(`/api/data?q=${this.props.query}`, {
                signal: this.controller.signal,
            });

            if (!response.ok) throw new Error("请求失败");

            const data = await response.json();
            this.setState({ data, loading: false });
        } catch (error) {
            if (error.name !== "AbortError") {
                this.setState({ error: error.message, loading: false });
            }
        }
    }

    render() {
        // 渲染逻辑
    }
}

性能优化

class OptimizedComponent extends React.PureComponent {
    // 使用 PureComponent 自动浅比较

    // 避免在 render 中创建新对象/函数
    get optimizedData() {
        // 计算属性
        return this.props.data.filter(item => item.active);
    }

    // 使用箭头函数避免绑定
    handleClick = () => {
        // 处理点击
    };

    // 复杂计算使用 memoization
    memoizedValue = null;
    lastComputeProps = null;

    getComputedValue() {
        if (this.lastComputeProps !== this.props.complexProp) {
            this.memoizedValue = expensiveComputation(this.props.complexProp);
            this.lastComputeProps = this.props.complexProp;
        }
        return this.memoizedValue;
    }

    render() {
        const computedValue = this.getComputedValue();

        return (
            <div>
                {this.optimizedData.map(item => (
                    <Item key={item.id} item={item} onClick={this.handleClick} />
                ))}
            </div>
        );
    }
}

动画和第三方库集成

class ChartComponent extends React.Component {
    chart = null;
    containerRef = React.createRef();

    componentDidMount() {
        // 初始化图表
        this.initChart();
    }

    componentDidUpdate(prevProps) {
        // 数据变化时更新图表
        if (this.props.data !== prevProps.data) {
            this.updateChart();
        }

        // 配置变化时重新初始化
        if (this.props.options !== prevProps.options) {
            this.destroyChart();
            this.initChart();
        }
    }

    componentWillUnmount() {
        // 清理图表
        this.destroyChart();
    }

    initChart() {
        this.chart = new Chart(this.containerRef.current, {
            type: "line",
            data: this.props.data,
            options: this.props.options,
        });
    }

    updateChart() {
        if (this.chart) {
            this.chart.data = this.props.data;
            this.chart.update();
        }
    }

    destroyChart() {
        if (this.chart) {
            this.chart.destroy();
            this.chart = null;
        }
    }

    render() {
        return <div ref={this.containerRef} />;
    }
}

常见生命周期误区

class CommonMistakes extends React.Component {
    // ❌ 错误:在 constructor 中基于 props 设置 state
    constructor(props) {
        super(props);
        this.state = {
            value: props.initialValue,
        };
    }

    // 问题:当 props 变化时,state 不会更新

    // ✅ 正确:使用 getDerivedStateFromProps
    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.initialValue !== prevState.prevInitialValue) {
            return {
                value: nextProps.initialValue,
                prevInitialValue: nextProps.initialValue,
            };
        }
        return null;
    }

    // ❌ 错误:在 componentDidUpdate 中无条件调用 setState
    componentDidUpdate() {
        this.setState({ updated: true }); // 导致无限循环
    }

    // ✅ 正确:添加条件判断
    componentDidUpdate(prevProps) {
        if (this.props.value !== prevProps.value) {
            this.setState({ updated: true });
        }
    }

    // ❌ 错误:在 render 中调用 setState
    render() {
        // this.setState({}); // 会导致无限循环
        return <div />;
    }

    // ❌ 错误:在 componentWillUnmount 中调用 setState
    componentWillUnmount() {
        // this.setState({}); // 组件已卸载,无法设置状态
    }
}

生命周期执行顺序示例

class ParentComponent extends React.Component {
    constructor(props) {
        super(props);
        console.log("Parent: constructor");
        this.state = { count: 0 };
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        console.log("Parent: getDerivedStateFromProps");
        return null;
    }

    componentDidMount() {
        console.log("Parent: componentDidMount");
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log("Parent: shouldComponentUpdate");
        return true;
    }

    getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log("Parent: getSnapshotBeforeUpdate");
        return "snapshot";
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("Parent: componentDidUpdate, 快照:", snapshot);
    }

    componentWillUnmount() {
        console.log("Parent: componentWillUnmount");
    }

    handleClick = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        console.log("Parent: render");
        return (
            <div>
                <h1>父组件</h1>
                <button onClick={this.handleClick}>更新</button>
                <ChildComponent count={this.state.count} />
            </div>
        );
    }
}

class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        console.log("Child: constructor");
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        console.log("Child: getDerivedStateFromProps");
        return null;
    }

    componentDidMount() {
        console.log("Child: componentDidMount");
    }

    // ... 其他生命周期方法

    render() {
        console.log("Child: render");
        return <div>子组件,计数: {this.props.count}</div>;
    }
}

// 控制台输出顺序:
// 挂载时:
// Parent: constructor
// Parent: getDerivedStateFromProps
// Parent: render
// Child: constructor
// Child: getDerivedStateFromProps
// Child: render
// Child: componentDidMount
// Parent: componentDidMount

// 更新时(点击按钮):
// Parent: getDerivedStateFromProps
// Parent: shouldComponentUpdate
// Parent: render
// Child: getDerivedStateFromProps
// Child: shouldComponentUpdate
// Child: render
// Parent: getSnapshotBeforeUpdate
// Child: getSnapshotBeforeUpdate
// Child: componentDidUpdate
// Parent: componentDidUpdate

总结

React 生命周期提供了组件在不同阶段的控制点:

  • 挂载阶段:初始化组件
  • 更新阶段:响应数据变化
  • 卸载阶段:清理资源
  • 错误处理:捕获和处理错误

现代 React 开发建议:

  • 新项目优先使用函数组件和 Hooks
  • 类组件中使用最新的生命周期方法
  • 避免使用已废弃的方法(UNSAFE_ 前缀的)
  • 在函数组件中,使用 useEffect 模拟生命周期
  • 合理使用错误边界提高应用健壮性