FumadocsZDecode
React

Class组件生命周期

React 类组件的生命周期分为三个阶段,每个阶段对应特定的钩子函数,让你在不同时机执行代码。


一、三个生命周期阶段

阶段触发时机对应函数
挂载组件被创建并插入 DOMconstructorrendercomponentDidMount
更新props 或 state 发生变化shouldComponentUpdaterendercomponentDidUpdate
卸载组件从 DOM 中移除componentWillUnmount

二、各阶段函数详解

挂载阶段

  • constructor:初始化 state,绑定方法,不执行副作用
  • render:返回 JSX,必须是纯函数
  • componentDidMount:组件挂载后,此时可以安全地发起网络请求、添加订阅、操作 DOM

更新阶段

  • shouldComponentUpdate(nextProps, nextState):返回 boolean,决定是否需要重新渲染,优化性能
  • render:重新渲染
  • componentDidUpdate(prevProps, prevState):更新完成后执行,常用于 props 变化时的操作或网络请求

卸载阶段

  • componentWillUnmount:清理定时器、取消网络请求、解除订阅

三、代码示例

class UserProfile extends React.Component<
  { userId: string },
  { user: null | { name: string; bio: string }; loading: boolean }
> {
  private timer: NodeJS.Timeout | null = null

  constructor(props: { userId: string }) {
    super(props)
    this.state = { user: null, loading: true }
  }

  componentDidMount() {
    // 组件挂载后获取数据
    this.fetchUser()
  }

  componentDidUpdate(prevProps: { userId: string }) {
    // userId 改变时重新获取用户数据
    if (prevProps.userId !== this.props.userId) {
      this.fetchUser()
    }
  }

  componentWillUnmount() {
    // 清理定时器和网络请求
    if (this.timer) clearTimeout(this.timer)
  }

  private fetchUser = () => {
    this.setState({ loading: true })
    this.timer = setTimeout(() => {
      this.setState({
        user: { name: 'John', bio: 'React Developer' },
        loading: false,
      })
    }, 1000)
  }

  shouldComponentUpdate(
    nextProps: { userId: string },
    nextState: { user: null | { name: string; bio: string }; loading: boolean },
  ) {
    // 只在 userId 或 user 改变时重新渲染
    return (
      nextProps.userId !== this.props.userId ||
      nextState.user !== this.state.user
    )
  }

  render() {
    const { user, loading } = this.state
    return (
      <div>
        {/* eslint-disable-next-line @stylistic/multiline-ternary*/}
        {loading ? (
          <p>Loading...</p>
        ) : (
          <p>
            {user?.name}: {user?.bio}{' '}
          </p>
        )}
      </div>
    )
  }
}

四、最佳实践

避免常见错误

  • 不在 constructor 中执行副作用或订阅
  • 不在 componentDidMount 中直接 setState(会触发额外渲染)
  • componentDidUpdate 中比较 props 以避免无限循环
  • 总是在 componentWillUnmount 中清理资源

现代替代方案

函数组件结合 useEffect Hook 是现在的首选,生命周期概念已逐步被 Effect 模型替代。


核心逻辑:挂载时初始化和获取数据,更新时响应 props 变化,卸载时清理资源——生命周期的本质是管理组件的副作用。

On this page