欢迎光临郴州转运服务网
详情描述

React生命周期是组件在不同阶段调用的特殊方法,主要用于控制组件的行为和优化性能。以下是React生命周期的演进、使用方式和实例解读:

一、生命周期演进

1. Class组件生命周期(16.3版本前)

Mounting(挂载阶段):
constructor → componentWillMount → render → componentDidMount

Updating(更新阶段):
componentWillReceiveProps → shouldComponentUpdate → componentWillUpdate → render → componentDidUpdate

Unmounting(卸载阶段):
componentWillUnmount

2. Class组件生命周期(16.3+版本)

Mounting:
constructor → static getDerivedStateFromProps → render → componentDidMount

Updating:
static getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshotBeforeUpdate → componentDidUpdate

Unmounting:
componentWillUnmount

3. 函数组件+Hooks

使用 useEffectuseState 等Hooks替代生命周期

二、常用生命周期方法详解

1. 挂载阶段

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    console.log('1. constructor');
  }

  static getDerivedStateFromProps(props, state) {
    console.log('2. getDerivedStateFromProps');
    // 根据props返回新的state
    return null;
  }

  componentDidMount() {
    console.log('4. componentDidMount');
    // 适合进行网络请求、DOM操作、事件订阅
    fetch('/api/data').then(response => {
      this.setState({ data: response.data });
    });
  }

  render() {
    console.log('3. render');
    return <div>{this.state.count}</div>;
  }
}

2. 更新阶段

class Example extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate');
    // 性能优化:决定是否重新渲染
    return this.state.count !== nextState.count;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate');
    // 获取更新前的DOM信息
    return { scrollHeight: document.body.scrollHeight };
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('componentDidUpdate');
    // 可以比较props/state变化
    if (this.props.userId !== prevProps.userId) {
      this.fetchData(this.props.userId);
    }

    // 使用snapshot恢复滚动位置
    if (snapshot) {
      const scrollDiff = document.body.scrollHeight - snapshot.scrollHeight;
      window.scrollTo(0, window.scrollY + scrollDiff);
    }
  }
}

3. 卸载阶段

class Example extends React.Component {
  componentWillUnmount() {
    console.log('componentWillUnmount');
    // 清理操作
    clearInterval(this.timerId);
    this.eventEmitter.removeListener('update', this.handleUpdate);
  }
}

三、Hooks替代方案

import React, { useState, useEffect, useMemo } from 'react';

function FunctionalComponent({ userId }) {
  const [data, setData] = useState(null);
  const [count, setCount] = useState(0);

  // componentDidMount + componentWillUnmount
  useEffect(() => {
    console.log('组件挂载');

    // 订阅事件
    const handleResize = () => console.log('resize');
    window.addEventListener('resize', handleResize);

    // 清理函数(componentWillUnmount)
    return () => {
      console.log('组件卸载');
      window.removeEventListener('resize', handleResize);
    };
  }, []); // 空数组表示只在挂载和卸载时执行

  // componentDidUpdate(监听特定props/state)
  useEffect(() => {
    if (userId) {
      fetchData(userId);
    }
  }, [userId]); // 依赖数组:userId变化时执行

  // 替代shouldComponentUpdate
  const memoizedValue = useMemo(() => {
    return computeExpensiveValue(count);
  }, [count]);

  // 替代getDerivedStateFromProps
  const derivedState = useMemo(() => {
    return propsToState(props);
  }, [props.someProp]);

  return <div>{data}</div>;
}

四、实用实例

1. 数据获取与取消

class UserProfile extends React.Component {
  state = { user: null, loading: true };

  componentDidMount() {
    this.fetchUser(this.props.userId);
  }

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

  componentWillUnmount() {
    // 防止组件卸载后setState
    this._isMounted = false;
    if (this.controller) {
      this.controller.abort(); // 取消fetch请求
    }
  }

  async fetchUser(userId) {
    this.controller = new AbortController();

    try {
      const response = await fetch(`/api/users/${userId}`, {
        signal: this.controller.signal
      });
      const user = await response.json();

      if (this._isMounted !== false) {
        this.setState({ user, loading: false });
      }
    } catch (error) {
      if (error.name !== 'AbortError') {
        console.error('Fetch error:', error);
      }
    }
  }
}

2. 错误边界(Error Boundaries)

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

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    // 可以记录错误到监控系统
    logErrorToService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <FallbackUI error={this.state.error} />;
    }
    return this.props.children;
  }
}

3. 性能优化示例

class ExpensiveComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    // 深度比较对象(实际项目建议使用浅比较)
    return !shallowEqual(this.props, nextProps);
  }

  render() {
    return <div>{/* 昂贵的渲染 */}</div>;
  }
}

// 使用React.memo的函数组件
const MemoizedComponent = React.memo(({ items }) => {
  return items.map(item => <Item key={item.id} item={item} />);
}, (prevProps, nextProps) => {
  // 自定义比较函数
  return prevProps.items.length === nextProps.items.length;
});

五、最佳实践建议

避免在render中执行副作用 componentDidMount中进行异步操作 使用shouldComponentUpdate或React.memo优化性能 在componentWillUnmount中清理资源 优先使用函数组件+Hooks getDerivedStateFromProps要谨慎使用,容易导致bug

六、生命周期图示

挂载时:
constructor
  ↓
getDerivedStateFromProps
  ↓
render
  ↓
componentDidMount

更新时:
getDerivedStateFromProps
  ↓
shouldComponentUpdate
  ↓
render
  ↓
getSnapshotBeforeUpdate
  ↓
componentDidUpdate

卸载时:
componentWillUnmount

理解React生命周期有助于编写更高效、更稳定的组件,但现代React开发更推荐使用函数组件和Hooks,它们提供了更简洁、更组合式的API。

相关帖子
外卖里吃出异物但已经咽下去了,还能不能主张赔偿?
外卖里吃出异物但已经咽下去了,还能不能主张赔偿?
2026年跨省考取的职业资格证书,在回到户籍地或工作地后能否申请相关补贴?
2026年跨省考取的职业资格证书,在回到户籍地或工作地后能否申请相关补贴?
2026年工伤保险政策有重要调整,灵活就业人员如何参保才能享受保障?
2026年工伤保险政策有重要调整,灵活就业人员如何参保才能享受保障?
无人机配送日益普及,其空域飞行需要遵守哪些具体的法律法规?
无人机配送日益普及,其空域飞行需要遵守哪些具体的法律法规?
早晚打胰岛素,中午血糖到了20怎么办
早晚打胰岛素,中午血糖到了20怎么办
宫颈癌放疗哪个部位好
宫颈癌放疗哪个部位好
在向物业投诉邻里噪音时,如何整理取证材料才能促使物业积极协调?
在向物业投诉邻里噪音时,如何整理取证材料才能促使物业积极协调?
濮阳精准获客助手#python开源cms二次开发,模板建站
濮阳精准获客助手#python开源cms二次开发,模板建站
舟山救护车转运病人-长途救护车租车电话
舟山救护车转运病人-长途救护车租车电话
达到法定退休年龄但社保缴费年限不足,有哪些途径可以补救或处理?
达到法定退休年龄但社保缴费年限不足,有哪些途径可以补救或处理?
小暑这天家家户户
小暑这天家家户户"晒伏",晒书晒衣到底图个啥,背后藏着哪些老讲究?
宁德病人转运120救护车租赁|急救车长途转运,24小时随叫随到
宁德病人转运120救护车租赁|急救车长途转运,24小时随叫随到
有数据显示,实施人车分流对减少社区内部交通事故的具体效果如何?
有数据显示,实施人车分流对减少社区内部交通事故的具体效果如何?
快递显示已签收但其实丢件了又没保价,这种情况维权第一步该做什么?
快递显示已签收但其实丢件了又没保价,这种情况维权第一步该做什么?
2026年快递为什么总被默认放驿站,想让快递员送货上门该怎么争取?
2026年快递为什么总被默认放驿站,想让快递员送货上门该怎么争取?
家里老人刚走,企业职工丧葬费和抚恤金到底能领多少,去哪个部门办?
家里老人刚走,企业职工丧葬费和抚恤金到底能领多少,去哪个部门办?
个人社保缴费记录和权益查询,2026年有哪些跨省通办线上渠道?
个人社保缴费记录和权益查询,2026年有哪些跨省通办线上渠道?
广州长途救护车护送病人回家-长途跨省救护车租车电话
广州长途救护车护送病人回家-长途跨省救护车租车电话
芜湖做网站公司#商城网站搭建,定制建站
芜湖做网站公司#商城网站搭建,定制建站
衢州救护车接送患者-120救护车租车电话
衢州救护车接送患者-120救护车租车电话
加急办理黄金抵押贷款技巧,依托流程知识缩短整体办理时长
加急办理黄金抵押贷款技巧,依托流程知识缩短整体办理时长