郴州中国转运服务网

React生命周期的使用与实例解读

2026-04-03 16:38:02 浏览次数:2
详细信息

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。

相关推荐