React 类生命周期 和 React Hooks 比对
React生命周期总结(旧、新生命周期以及Hooks)
理解什么是生命周期?
当我们使用各种框架开发程序时,当这个框架启动、程序刚运行时、各个页面之间的交互、数据渲染到页面上面、程序运行结束,应当会有个闭环的操作,而在这个环的起点和终点之间的各个节点,框架给给定一些特定函数供我们自行调用,方便我们执行一些操作,这便是生命周期。react也是如此
react有哪些生命周期函数和作用
类组件中的生命周期:
类组件的生命周期主要分为三个阶段:初始化阶段、更新阶段、卸载阶段
初始化阶段:也成组件挂载阶段,这个阶段会执行初次加载组件到第一次渲染到界面上的一系列钩子函数,用于初始化状态和绑定方法。
执行流程为:constructor->componentWillMount->render->componentDidMount
constructor:这是一个构造器,这里面可以接收一个父组件传来的props然后初始化state值 用于初始化值和方法
componentWillMount: 组件将要挂载,render之前会执行这个函数,也就说会在渲染浏览器dom之前执行这个函数,无实际用处
render:常用且重要的钩子函数之一。render执行完后便会将html标签及自定义的函数等这些语句对应渲染到浏览器上面
componentDidMount:组件挂载完毕后立即执行,可以操作DOM 适用于网络请求、数据获取、订阅等副作用
更新阶段:什么时候会执行更新阶段这一系列的钩子函数呢,那自然是我们在更新了state值的时候或者是接收到父组件props值的时
常规流程是:componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
componentWillReceiveProps:当子组件收到父组件传过来的props,会执行这个函数
shouldComponentUpdate:当更新state值的时会执行这个函数,适用于控制组件是否需要重新渲染。返回 false 可阻止更新,优化性能
componentWillUpdate:里面会有两个参数nextProps, nextState,这是将要渲染的props和state的值,为即将发生的重新渲染做准备
render: 和初始化时候执行的那个render一样,只是这里是更新值的,所以dom节点会重新更新一下。
componentDidUpdate: 组件更新完毕执行的钩子函数。适合执行 DOM 操作或网络请求
卸载阶段:当组件卸载时执行的钩子函数,这里只有一个,那就是componentWillUnmount
componentWillUnmount:组件卸载前调用。 用于清理定时器、取消网络请求、移除订阅等
错误处理:
getDerivedStateFromError:后代组件抛出错误后调用,返回一个 state 更新
componentDidCatch:捕获后代组件的错误,可用于记录错误信息
React17版本之后,废除了 componentWillMount、componentWillReceiveProps、componentWillUpdate 这个三个钩子函数,取而代之的是
getDerivedStateFromProps,其实是把这三个钩子函数融入到这一个钩子函数中,同时还新增了一个钩子函数 getSnapshotBeforeUpdate
新版生命周期执行顺序
getDerivedStateFromProps:返回一个对象来更新 state,或返回 null 不更新
getSnapshotBeforeUpdate:在 DOM 更新前捕获一些信息(如滚动位置)
挂载阶段:constructor->getDerivedStateFromProps->render->componentDidMount
更新阶段:getDerivedStateFromProps->shouldComponentUpdate->getSnapshotBeforeUpdate->render->componentDidUpdate
卸载阶段:componentWillUnmount
React Hooks: React Hooks 提供了一种更简洁的方式来管理函数组件的状态和副作用,同时也能模拟类组件中的生命周期方法
基础生命周期对照:
1、constructor → useState/useReducer
// 类组件
constructor(props) {super(props);this.state = { count: 0 };
}// 函数组件
const [count, setCount] = useState(0);
2、componentDidMount → useEffect 空依赖数组
// 类组件
componentDidMount() {console.log('组件已挂载');// 初始化操作
}// 函数组件
useEffect(() => {console.log('组件已挂载');// 初始化操作
}, []); // 空数组表示只在挂载时执行
3、componentDidUpdate → useEffect 带依赖
// 类组件
componentDidUpdate(prevProps, prevState) {if (this.state.count !== prevState.count) {console.log('count 已更新');}
}// 函数组件
useEffect(() => {console.log('count 已更新:', count);
}, [count]); // 只在 count 变化时执行
4、componentWillUnmount → useEffect 的清理函数
// 类组件
componentWillUnmount() {console.log('组件即将卸载');// 清理操作
}// 函数组件
useEffect(() => {return () => {console.log('组件即将卸载');// 清理操作};
}, []);
高级生命周期对应关系
1、shouldComponentUpdate → React.memo 或 useMemo
// 类组件
shouldComponentUpdate(nextProps, nextState) {return nextProps.value !== this.props.value;
}// 函数组件
const MyComponent = React.memo(function MyComponent(props) {/* 只在 props 变化时重新渲染 */
});// 或者使用 useMemo 优化部分渲染
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
2、getDerivedStateFromProps → useState + useEffect
// 类组件
static getDerivedStateFromProps(props, state) {if (props.value !== state.prevValue) {return {derivedData: props.value * 2,prevValue: props.value};}return null;
}// 函数组件
function MyComponent({ value }) {const [derivedData, setDerivedData] = useState(value * 2);const [prevValue, setPrevValue] = useState(value);if (value !== prevValue) {setDerivedData(value * 2);setPrevValue(value);}// 或者使用 useEffectuseEffect(() => {setDerivedData(value * 2);}, [value]);
}
3、getSnapshotBeforeUpdate 和 componentDidUpdate → useLayoutEffect
// 类组件
getSnapshotBeforeUpdate(prevProps, prevState) {if (prevProps.list.length < this.props.list.length) {return this.listRef.scrollHeight;}return null;
}componentDidUpdate(prevProps, prevState, snapshot) {if (snapshot !== null) {this.listRef.scrollTop += this.listRef.scrollHeight - snapshot;}
}// 函数组件
const listRef = useRef();useLayoutEffect(() => {if (listRef.current) {const { scrollHeight, scrollTop, clientHeight } = listRef.current;if (scrollTop + clientHeight === scrollHeight) {// 自动滚动到底部listRef.current.scrollTop = scrollHeight;}}
}, [list]); // 依赖列表数据
完整的生命周期案例
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react';function LifecycleHooksExample({ initialCount }) {// 对应 constructor 和 stateconst [count, setCount] = useState(initialCount);const [prevCount, setPrevCount] = useState(null);const [data, setData] = useState(null);const [isLoading, setIsLoading] = useState(false);const timerRef = useRef();const divRef = useRef();// 对应 getDerivedStateFromPropsif (initialCount !== prevCount) {setCount(initialCount);setPrevCount(initialCount);}// 对应 componentDidMountuseEffect(() => {console.log('组件已挂载');fetchData();// 设置定时器timerRef.current = setInterval(() => {console.log('定时器运行中...');}, 1000);// 对应 componentWillUnmount 的清理函数return () => {console.log('组件即将卸载');clearInterval(timerRef.current);};}, []);// 对应 componentDidUpdate 特定 state/props 变化useEffect(() => {if (count > 10) {console.log('count 大于 10');}}, [count]);// 对应 getSnapshotBeforeUpdate + componentDidUpdateuseLayoutEffect(() => {if (divRef.current) {console.log('DOM 已更新,可以获取最新布局信息');console.log('div 高度:', divRef.current.clientHeight);}});const fetchData = async () => {setIsLoading(true);try {const response = await fetch('https://api.example.com/data');const result = await response.json();setData(result);} catch (error) {console.error('获取数据失败:', error);} finally {setIsLoading(false);}};const increment = () => {setCount(c => c + 1);};return (<div ref={divRef}><h2>生命周期 Hooks 示例</h2><p>当前计数: {count}</p><button onClick={increment}>增加</button>{isLoading ? (<p>加载中...</p>) : (data && <pre>{JSON.stringify(data, null, 2)}</pre>)}</div>);
}