一、生命周期三个阶段
- 挂载阶段(Mounting)
- 更新阶段(Updating)
- 卸载阶段(Unmounting)
二、生命周期方法详解(简化版)
1. 挂载阶段
方法 | 触发时机 | 用途 | 注意事项 |
---|
constructor() | 组件初始化时 | 初始化 state ,绑定事件处理函数 | 避免直接调用 setState ,仅用于初始化。 |
render() | 必须实现,返回 JSX | 渲染 UI | 不可调用 setState ,否则导致无限循环。 |
componentDidMount() | 组件挂载到 DOM 后 | 发起网络请求、操作 DOM、订阅事件 | 可调用 setState ,触发重新渲染。 |
2. 更新阶段
方法 | 触发时机 | 用途 | 注意事项 |
---|
shouldComponentUpdate(nextProps, nextState) | 在重新渲染前 | 通过返回 true/false 控制是否渲染 | 用于性能优化,避免不必要的渲染。 |
render() | 同挂载阶段 | 同挂载阶段 | 同上 |
componentDidUpdate(prevProps, prevState) | 组件更新完成后 | 操作更新后的 DOM、发送请求 | 避免直接调用 setState ,需条件判断防止死循环。 |
3. 卸载阶段
方法 | 触发时机 | 用途 |
---|
componentWillUnmount() | 组件卸载前 | 清理定时器、取消请求、移除事件监听 |
三、过时的生命周期方法(React 16.3+ 已废弃)
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate()
替代方案:
- 使用
props
直接控制组件行为(受控组件模式)。 - 使用
componentDidUpdate
处理更新后的逻辑。
四、函数组件与 Hooks 的等效实现
类组件生命周期 | 函数组件实现方式 |
---|
componentDidMount | useEffect(() => { ... }, []) (空依赖数组) |
componentDidUpdate | useEffect(() => { ... }) (无依赖数组,或依赖特定状态) |
componentWillUnmount | useEffect(() => { return () => { cleanup } }, []) (返回清理函数) |
shouldComponentUpdate | React.memo() (包裹组件,浅比较 props)或 useMemo /useCallback 优化渲染 |
五、关键注意事项
- 避免在
render
中调用 setState
:会导致无限循环。 - 优先使用受控组件:通过
props
和 state
管理数据流,而非依赖生命周期处理派生状态。 - 错误边界:使用
static getDerivedStateFromError()
或 componentDidCatch()
捕获子组件错误(类组件专属)。
六、最佳实践
- 网络请求:放在
componentDidMount
(类组件)或 useEffect
(函数组件)。 - 副作用清理:定时器、事件监听等务必在
componentWillUnmount
或 useEffect
的清理函数中移除。 - 性能优化:
- 类组件:继承
PureComponent
自动浅比较 props/state
。 - 函数组件:使用
React.memo
、useMemo
、useCallback
。
总结
在不考虑复杂且易出错的 getDerivedStateFromProps
和 getSnapshotBeforeUpdate
的情况下,React 生命周期更简洁,核心逻辑围绕以下方法:
- 挂载阶段:
constructor
→ render
→ componentDidMount
- 更新阶段:
shouldComponentUpdate
→ render
→ componentDidUpdate
- 卸载阶段:
componentWillUnmount
推荐迁移到函数组件 + Hooks,代码更简洁且易于维护,无需关注复杂生命周期。例如:
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(res => setData(res));
return () => {
cancelRequest();
};
}, []);
return <div>{data}</div>;
}