当前位置:  首页>> 技术小册>> 深入学习React实战进阶

05 | React组件的生命周期及其使用场景

在React的广阔世界中,组件是构建用户界面的基石。理解React组件的生命周期(Lifecycle)对于高效、可维护的React应用开发至关重要。组件的生命周期是指一个组件从创建到销毁所经历的一系列阶段,React通过提供一系列的生命周期方法(Hooks之前的旧版React)或Hooks(React 16.8+引入),允许开发者在这些特定阶段插入代码,以实现复杂的逻辑和交互。本章节将深入探讨React组件的生命周期,包括旧版生命周期方法、Hooks的引入以及它们在不同使用场景下的应用。

一、React组件生命周期概述

在React 16.8之前,组件的生命周期主要通过一系列的生命周期方法来表达,这些方法在组件的不同阶段被自动调用。主要可以分为三类:挂载(Mounting)、更新(Updating)、卸载(Unmounting)。

  1. 挂载(Mounting):组件实例化并插入到DOM中的过程。

    • constructor(props):构造函数,用于初始化组件状态。
    • static getDerivedStateFromProps(props, state)(类组件特有,用于替代componentWillReceiveProps):在实例化过程中和接收到新的props时调用,返回对象来更新state,或者返回null表示新的props不需要更新任何state。
    • render():唯一必须实现的方法,用于输出组件的UI。
    • componentDidMount():在组件挂载后立即调用,是进行DOM操作、网络请求等副作用操作的理想位置。
  2. 更新(Updating):组件的props或state发生变化时,组件会重新渲染。

    • static getSnapshotBeforeUpdate(prevProps, prevState)(类组件特有):在最新的渲染输出提交给DOM之前调用,允许你捕获一些信息(如滚动位置)并传递给componentDidUpdate
    • shouldComponentUpdate(nextProps, nextState):在组件更新之前调用,返回一个布尔值决定组件是否应该重新渲染。默认返回true,但在优化性能时非常有用。
    • render():重新渲染组件。
    • getDerivedStateFromProps(props, state)(再次提及,因可能在更新过程中被调用)。
    • componentDidUpdate(prevProps, prevState, snapshot):在更新发生后立即调用,适合执行依赖于DOM变更的操作。
  3. 卸载(Unmounting):组件从DOM中移除的过程。

    • componentWillUnmount():在组件卸载及销毁之前直接调用。清理定时器、取消网络请求、移除事件监听器等副作用操作应在此方法中完成。

二、Hooks引入后的生命周期变化

React 16.8引入了Hooks,旨在解决类组件的某些限制,并使得函数组件能够使用状态和其他React特性。Hooks并不直接对应传统的生命周期方法,但它们提供了在函数组件中执行类似操作的能力。

  • useEffect:用于替代componentDidMountcomponentDidUpdatecomponentWillUnmount等生命周期方法。通过传入一个函数和一个依赖项数组,可以在组件挂载后、更新后执行副作用操作,并在组件卸载前进行清理。
  • useLayoutEffect:类似于useEffect,但它在所有的DOM变更之后同步调用,适合需要读取DOM布局或执行重绘之前的操作。

三、使用场景示例

1. 组件挂载后立即发起网络请求

componentDidMountuseEffect中发起网络请求是常见的使用场景。这种方式确保了组件在挂载到DOM之后立即从服务器获取数据,从而避免了不必要的渲染。

  1. // 类组件示例
  2. class MyComponent extends React.Component {
  3. componentDidMount() {
  4. fetchData().then(data => this.setState({ data }));
  5. }
  6. // ...
  7. }
  8. // 函数组件 + Hooks示例
  9. function MyComponent() {
  10. const [data, setData] = useState(null);
  11. useEffect(() => {
  12. fetchData().then(data => setData(data));
  13. }, []); // 空数组表示只在挂载时执行
  14. // ...
  15. }
2. 根据props变化更新组件状态

在类组件中,你可能会使用componentWillReceivePropsgetDerivedStateFromProps来根据props的变化更新state。但推荐使用getDerivedStateFromProps,因为它更靠近渲染过程,并且避免了在即将卸载的组件上调用。

  1. // 类组件示例
  2. static getDerivedStateFromProps(props, state) {
  3. if (props.value !== state.controlledValue) {
  4. return { controlledValue: props.value };
  5. }
  6. return null;
  7. }
  8. // 函数组件通常不需要这样的逻辑,因为props可以直接在render中使用
3. 性能优化:避免不必要的渲染

shouldComponentUpdate是性能优化的重要工具,它允许你基于当前和下一个props及state来决定组件是否需要更新。在函数组件中,虽然没有直接对应的生命周期方法,但可以通过React.memo和useMemo、useCallback等Hooks来优化。

  1. // 类组件示例
  2. shouldComponentUpdate(nextProps, nextState) {
  3. // 逻辑判断
  4. return this.props.id !== nextProps.id;
  5. }
  6. // 函数组件 + React.memo示例
  7. const MyComponent = React.memo(function MyComponent(props) {
  8. // ...
  9. }, (prevProps, nextProps) => prevProps.id === nextProps.id);
4. 组件卸载前的清理工作

在组件卸载前,需要清理诸如定时器、事件监听器或取消网络请求等副作用。在类组件中,这通常在componentWillUnmount中完成。

  1. // 类组件示例
  2. componentWillUnmount() {
  3. clearTimeout(this.timer);
  4. this.someEventListener.remove();
  5. }
  6. // 函数组件 + useEffect示例
  7. useEffect(() => {
  8. const timer = setTimeout(() => {
  9. // 逻辑
  10. }, 1000);
  11. return () => {
  12. clearTimeout(timer);
  13. // 清理其他副作用
  14. };
  15. }, []);

四、总结

React组件的生命周期是理解React组件行为的关键。无论是通过传统的生命周期方法还是现代的Hooks,掌握它们的使用场景和最佳实践对于构建高效、可维护的React应用至关重要。随着React版本的迭代,我们见证了从类组件到函数组件+Hooks的转变,这不仅简化了代码结构,也提供了更灵活、更强大的编程模式。深入理解这些概念,将帮助你更好地驾驭React的力量,开发出更加优秀的Web应用。


该分类下的相关小册推荐: