React 生命周期

React 生命周期可以分为三个主要阶段:挂载(Mounting)、更新(Updating)和卸载(Unmounting)

挂载(Mounting)

当组件实例被创建并插入到 DOM 中时,会依次调用以下方法:

constructor(props)

javascript 复制代码
// 1.初始化组件的状态。
// 2.绑定事件处理器方法。
// 3.注意:不要在构造函数中调用 setState() 方法。
constructor(props) {
  super(props);
  this.state = {
    count: 0
  };
}

static getDerivedStateFromProps(props, state)

javascript 复制代码
// 1.在组件渲染之前调用,返回一个对象来更新 state,或者返回 null 表示不更新任何内容。
// 2.注意:这个方法很少使用,因为它容易导致代码难以维护。
static getDerivedStateFromProps(props, state) {
  if (props.value !== state.externalValue) {
    return { externalValue: props.value };
  }
  return null;
}

render()

javascript 复制代码
// 1.必须实现的方法,返回 React 元素、数组、片段、门户、字符串、数字或 null。
// 2.注意:不要在 render() 方法中调用 setState() 方法.
render() {
  return <h1>Hello, {this.state.name}</h1>;
}

componentDidMount()

javascript 复制代码
// 1.在组件挂载后立即调用。
// 2.适合进行网络请求、订阅事件等操作。
// 3.注意:可以在这里调用 setState() 方法,但会导致额外的重新渲染。
componentDidMount() {
  fetch('/api/data')
    .then(response => response.json())
    .then(data => this.setState({ data }));
}

更新(Updating)

当组件的 props 或 state 发生变化时,会依次调用以下方法:

static getDerivedStateFromProps(props, state)- 在组件重新渲染之前调用,注意:与挂载阶段相同。

shouldComponentUpdate(nextProps, nextState)

javascript 复制代码
// 1.返回一个布尔值,决定组件是否应该重新渲染。
// 2.默认返回 true,即组件会在每次更新时重新渲染。
// 3.注意:可以通过优化性能,避免不必要的重新渲染。
shouldComponentUpdate(nextProps, nextState) {
  return nextProps.value !== this.props.value || nextState.count !== this.state.count;
}

**render()-**与挂载阶段相同

getSnapshotBeforeUpdate(prevProps, prevState)

javascript 复制代码
// 1.在最近一次渲染输出提交到 DOM 之前调用。
// 2.返回一个值,作为 componentDidUpdate 的第三个参数。
// 3.注意:很少使用,通常用于从 DOM 中捕获一些信息(如滚动位置)。
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)

javascript 复制代码
// 1.在组件更新后立即调用。
// 2.可以在这里进行网络请求,但需要比较当前 props 和 prevProps。
// 3.注意:可以在这里调用 setState() 方法,但需要小心避免无限循环。
componentDidUpdate(prevProps, prevState, snapshot) {
  if (snapshot !== null) {
    const list = this.listRef.current;
    list.scrollTop = list.scrollHeight - snapshot;
  }
}

卸载(Unmounting)

当组件从 DOM 中移除时,会调用以下方法:

componentWillUnmount()

javascript 复制代码
// 1. 在组件卸载和销毁之前调用。
// 2. 适合进行清理工作,如取消网络请求、清除定时器、取消事件订阅等。
// 3. 注意:不要调用 setState() 方法,因为组件即将被卸载。
componentWillUnmount() {
  clearInterval(this.timerID);
}

错误处理(Error Handling)

static getDerivedStateFromError(error)

javascript 复制代码
// 1.在后代组件抛出错误后调用。
// 2.返回一个对象来更新 state。
// 3.注意:用于渲染备用 UI。
static getDerivedStateFromError(error) {
  return { hasError: true };
}

componentDidCatch(error, info)

javascript 复制代码
// 1.在后代组件抛出错误后调用。
// 2.适合记录错误信息。
// 3.注意:可以在这里调用 setState() 方法。
componentDidCatch(error, info) {
  console.error("Error caught:", error, info);
}

应用计算器

javascript 复制代码
// src/components/Counter.js
import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    console.log('Constructor called');
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('getDerivedStateFromProps called');
    return null; // 返回 null 表示不修改 state
  }

  componentDidMount() {
    console.log('componentDidMount called');
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate called');
    return true; // 返回 true 表示允许更新
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate called');
    return null; // 返回值将作为 componentDidUpdate 的第三个参数
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('componentDidUpdate called');
  }

  componentWillUnmount() {
    console.log('componentWillUnmount called');
  }

  incrementCount = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1
    }));
  };

  render() {
    console.log('Render called');
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={this.incrementCount}>Increment</button>
      </div>
    );
  }
}

export default Counter;
javascript 复制代码
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from './components/Counter';

ReactDOM.render(<Counter />, document.getElementById('root'));

总结

  1. 挂载(Mounting):初始化组件、绑定事件、获取数据。
  2. 更新(Updating):响应 props 和 state 的变化,优化性能。
  3. 卸载(Unmounting):清理资源,避免内存泄漏。
  4. 错误处理(Error Handling):捕获和处理错误,提供更好的用户体验。
  5. 挂载阶段constructor -> getDerivedStateFromProps -> render -> componentDidMount
  6. 更新阶段getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
  7. 卸载阶段componentWillUnmount
  8. useEffect :替代 componentDidMountcomponentDidUpdatecomponentWillUnmount
  9. useState:管理组件状态。
  10. useMemouseCallback:优化性能,避免不必要的重新渲染。
相关推荐
yrldjsbk2 分钟前
使用vue.js第三版本vite构建一个简单的在线敲击木鱼网站Demo
前端·javascript·vue.js
这不比博人传燃?14 分钟前
传奇996_60——lua前端详解
前端·游戏引擎
计算机毕设定制辅导-无忧学长24 分钟前
基于HTML的个人博客系统的设计与实现
java·前端·css·spring boot·html5
xChive1 小时前
各大坐标系统的关系以及在uniapp中的应用
前端·百度·uni-app·地图·坐标系·高德
m0_748257461 小时前
Vue3 基本使用 Monaco Editor Web编辑器 202407
前端·arcgis·编辑器
上趣工作室1 小时前
uniapp中打包应用后,组件在微信小程序和其他平台实现不同的样式
前端·vue.js·微信小程序·小程序·uni-app
小小优化师 anny1 小时前
flex 弹性布局 笔记
前端·javascript·css
哟哟耶耶1 小时前
component-流程进度(不借用组件)
前端·css·html
Gzzz__1 小时前
vue 3使用Element Plus Calendar 组件显示农历及节日
前端·vue.js·elementui·节日
那就可爱多一点点1 小时前
本地如何使用 yarn link 调试本地 npm 包
前端·npm·node.js