React 生命周期完整指南
1. 生命周期概述
1.1 React 16.3 之前的生命周期
- 初始化阶段
- constructor
- componentWillMount
- render
- componentDidMount
 
- 更新阶段
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
 
- 卸载阶段
- componentWillUnmount
 
1.2 React 16.3 之后的生命周期
- 初始化阶段
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
 
- 更新阶段
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
 
- 卸载阶段
- componentWillUnmount
 
2. 详细说明
2.1 挂载阶段
            
            
              jsx
              
              
            
          
          class MyComponent extends React.Component {
  // 1. 构造函数
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    console.log('1. constructor');
  }
  // 2. 派生状态
  static getDerivedStateFromProps(props, state) {
    console.log('2. getDerivedStateFromProps');
    return null;
  }
  // 3. 渲染
  render() {
    console.log('3. render');
    return <div>{this.state.count}</div>;
  }
  // 4. 挂载完成
  componentDidMount() {
    console.log('4. componentDidMount');
  }
}2.2 更新阶段
            
            
              jsx
              
              
            
          
          class UpdateComponent extends React.Component {
  // 1. 派生状态
  static getDerivedStateFromProps(props, state) {
    console.log('1. getDerivedStateFromProps');
    return null;
  }
  // 2. 是否应该更新
  shouldComponentUpdate(nextProps, nextState) {
    console.log('2. shouldComponentUpdate');
    return true;
  }
  // 3. 渲染
  render() {
    console.log('3. render');
    return <div>{this.state.count}</div>;
  }
  // 4. 获取更新前的快照
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('4. getSnapshotBeforeUpdate');
    return null;
  }
  // 5. 更新完成
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('5. componentDidUpdate');
  }
}2.3 卸载阶段
            
            
              jsx
              
              
            
          
          class UnmountComponent extends React.Component {
  componentWillUnmount() {
    console.log('componentWillUnmount');
    // 清理工作:取消订阅、清除定时器等
  }
}3. 新旧生命周期对比
3.1 被移除的生命周期方法
componentWillMount
            
            
              jsx
              
              
            
          
          // 旧版本
componentWillMount() {
  // 组件即将挂载
  // 问题:可能会导致服务器端渲染问题
}
// 新版本替代方案
componentDidMount() {
  // 组件已挂载
  // 建议在这里进行异步操作
}componentWillReceiveProps
            
            
              jsx
              
              
            
          
          // 旧版本
componentWillReceiveProps(nextProps) {
  // 即将接收新的 props
  if (nextProps.value !== this.props.value) {
    this.setState({ value: nextProps.value });
  }
}
// 新版本替代方案
static getDerivedStateFromProps(props, state) {
  if (props.value !== state.value) {
    return { value: props.value };
  }
  return null;
}componentWillUpdate
            
            
              jsx
              
              
            
          
          // 旧版本
componentWillUpdate(nextProps, nextState) {
  // 即将更新
  // 问题:可能会导致异步渲染问题
}
// 新版本替代方案
getSnapshotBeforeUpdate(prevProps, prevState) {
  // 获取更新前的快照
  return null;
}3.2 新增的生命周期方法
getDerivedStateFromProps
            
            
              jsx
              
              
            
          
          class Example extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // 返回新状态或 null
    if (props.currentRow !== state.lastRow) {
      return {
        isScrollingDown: props.currentRow > state.lastRow,
        lastRow: props.currentRow
      };
    }
    return null;
  }
}getSnapshotBeforeUpdate
            
            
              jsx
              
              
            
          
          class ScrollingList extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 捕获更新前的信息
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    // 使用快照信息
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }
}4. 生命周期最佳实践
4.1 常见用途
            
            
              jsx
              
              
            
          
          class BestPractices extends React.Component {
  constructor(props) {
    super(props);
    // 初始化状态
    // 绑定方法
  }
  static getDerivedStateFromProps(props, state) {
    // 用于状态的派生
    // 不要在这里执行副作用
    return null;
  }
  componentDidMount() {
    // 适合执行副作用
    // - 网络请求
    // - DOM 操作
    // - 订阅
  }
  shouldComponentUpdate(nextProps, nextState) {
    // 性能优化
    // 返回 false 可以阻止更新
    return true;
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 获取 DOM 更新前的信息
    return null;
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    // 更新后的操作
    // 可以执行副作用
    // 注意避免无限循环
  }
  componentWillUnmount() {
    // 清理工作
    // - 取消订阅
    // - 清除定时器
    // - 取消网络请求
  }
}4.2 错误处理
            
            
              jsx
              
              
            
          
          class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError(error) {
    // 更新状态,下次渲染时显示降级 UI
    return { hasError: true };
  }
  componentDidCatch(error, errorInfo) {
    // 记录错误信息
    console.error('Error:', error);
    console.error('Error Info:', errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}5. Hooks 时代的生命周期
5.1 使用 Hooks 模拟生命周期
            
            
              jsx
              
              
            
          
          function HooksLifecycle() {
  // 模拟 constructor
  const [state, setState] = useState({
    count: 0
  });
  // 模拟 componentDidMount
  useEffect(() => {
    console.log('Component mounted');
    return () => {
      // 模拟 componentWillUnmount
      console.log('Component will unmount');
    };
  }, []);
  // 模拟 componentDidUpdate
  useEffect(() => {
    console.log('State updated:', state);
  }, [state]);
  return <div>{state.count}</div>;
}5.2 生命周期方法与 Hooks 对照表
| 生命周期方法 | Hooks 实现 | 
|---|---|
| constructor | useState | 
| componentDidMount | useEffect(() => {}, []) | 
| componentDidUpdate | useEffect(() => {}, [deps]) | 
| componentWillUnmount | useEffect(() => { return () => {} }, []) | 
| shouldComponentUpdate | useMemo, useCallback | 
| getDerivedStateFromProps | useState + useEffect | 
6. 总结
6.1 生命周期选择建议
- 使用 componentDidMount进行初始化操作
- 使用 componentDidUpdate响应更新
- 使用 componentWillUnmount清理资源
- 优先考虑新的生命周期方法
- 在合适的场景使用 Hooks
6.2 注意事项
- 避免在构造函数中执行副作用
- 不要在 getDerivedStateFromProps中执行副作用
- 谨慎使用 shouldComponentUpdate
- 在 componentDidUpdate中注意避免无限循环
- 确保在 componentWillUnmount中清理所有副作用
6.3函数组件中的生命周期(通过 Hooks)
useEffect 可以模拟 componentDidMount 和 componentDidUpdate,通过将依赖项传递给 useEffect 来控制副作用的执行。传递空数组 [] 作为依赖项时,useEffect 只会在组件首次挂载时执行,相当于 componentDidMount。
清理副作用:useEffect 可以返回一个清理函数,相当于类组件中的 componentWillUnmount。
import React, { useState, useEffect } from 'react';
const MyFunctionComponent = () => {
  const [counter, setCounter] = useState(0);
  // 模拟 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    console.log('组件已挂载或更新');
    
    // 模拟 componentWillUnmount
    return () => {
      console.log('组件将卸载');
    };
  }, [counter]);  // 依赖项,只有当 counter 更新时,才会重新执行 useEffect
  return (
    <div>
      <p>Counter: {counter}</p>
      <button onClick={() => setCounter(counter + 1)}>增加计数</button>
    </div>
  );
};
export default MyFunctionComponent;6.4 React 18 的新特性
React 18 引入了多个新特性,最显著的之一是 并发模式(Concurrent Mode),它改善了渲染性能,尤其是在 React 应用的响应式方面。虽然并发模式与生命周期方法的直接关系不大,但它会影响组件的挂载、更新和卸载过程。
React 18 还引入了 自动批量更新(Automatic Batching)和 Suspense 进一步增强了异步渲染的能力。这些新特性和生命周期方法并没有冲突,而是增强了现有的机制。
总结:
类组件:React 18 中,类组件的生命周期方法仍然有效,且与之前的版本一样。
函数组件:函数组件使用 useEffect 和其他 Hooks 来模拟传统的生命周期方法。
React 18 新特性:引入了并发模式、自动批量更新等,但它不会影响生命周期方法。
因此,如果你使用类组件,React 18 中依然可以使用传统的生命周期方法。如果使用函数组件,你可以通过 useEffect 来替代和模拟传统生命周期的行为。