目录
挂载阶段
constructor()
render()
JavaScript Tools
componentDidMount()
static getDerivedStateFromProps()
更新阶段
shouldComponentUpdate()
getSnapshotBeforeUpdate()
componentDidUpdate()
卸载阶段
错误处理阶段
getDerivedStateFromError()
Oops, something went wrong :(
componentDidCatch()
这就是React组件的生命周期!
首页 web前端 css教程 反应生命周期的圆

反应生命周期的圆

Apr 21, 2025 am 09:35 AM

The Circle of a React Lifecycle

React组件在其应用生命周期中会经历不同的阶段,尽管幕后发生的事情可能并不明显。

这些阶段包括:

  • 挂载
  • 更新
  • 卸载
  • 错误处理

每个阶段都有相应的方法,可以在该阶段对组件执行特定操作。例如,当从网络获取数据时,您可能希望在componentDidMount()方法(在挂载阶段可用)中调用处理API调用的函数。

了解不同的生命周期方法对于React应用程序的开发至关重要,因为它允许我们在需要时精确地触发操作,而不会与其他操作混淆。本文将介绍每个生命周期,包括可用的方法以及我们使用它们的场景类型。

挂载阶段

挂载视为组件生命周期的初始阶段。在挂载发生之前,组件尚未存在——它只是DOM中的一闪而过,直到挂载发生并将其作为文档的一部分连接起来。

一旦组件挂载,我们就可以利用许多方法:constructor()render()componentDidMount()static getDerivedStateFromProps()。每个方法都有其自身的用途,让我们按顺序来看一下。

constructor()

当直接在组件上设置状态以将方法绑定在一起时,需要constructor()方法。它看起来像这样:

// 一旦输入组件开始挂载...
constructor(props) {
  // ...设置一些props...
  super(props);
  // ...在这种情况下,是一个空白用户名...
  this.state = {
    username: ''
  };
  // ...然后绑定一个处理输入更改的方法
  this.handleInputChange = this.handleInputChange.bind(this);
}
登录后复制

重要的是要知道,constructor是创建组件时调用的第一个方法。组件尚未渲染(即将到来),但DOM已经知道它,我们可以在它渲染之前与它挂钩。因此,这不是我们调用setState()或引入任何副作用的地方,因为组件仍然处于构建阶段!

我之前写过一篇关于refs的教程,我注意到的一件事是在使用React.createRef()时,可以在constructor中设置ref。这是合理的,因为refs用于更改值而无需props或必须使用更新值重新渲染组件:

constructor(props) {
  super(props);
  this.state = {
    username: ''
  };
  this.inputText = React.createRef();
}
登录后复制

render()

render()方法是组件的标记在前端显示的地方。用户此时可以看到并访问它。如果您曾经创建过React组件,那么您已经熟悉它了——即使您没有意识到——因为它需要输出标记。

class App extends React.Component {
  // 挂载过程中,请渲染以下内容!
  render() {
    return (
      <div>
        <p>Hello World!</p>
      </div>
    )
  }
}
登录后复制

但这并不是render()的全部用途!它还可以用于渲染组件数组:

class App extends React.Component {
  render () {
    return [
      <h2 id="JavaScript-Tools">JavaScript Tools</h2>,
      <frontend></frontend>,
      <backend></backend>
    ]
  }
}
登录后复制

甚至组件片段:

class App extends React.Component {
  render() {
    return (
      <react.fragment><p>Hello World!</p></react.fragment>
    )
  }
}
登录后复制

我们还可以使用它来渲染DOM层次结构之外的组件(类似于React Portal):

// 我们正在创建一个门户,允许组件在DOM中移动
class Portal extends React.Component {
  // 首先,我们创建一个div元素
  constructor() {
    super();
    this.el = document.createElement("div");
  }

  // 挂载后,让我们追加组件的子元素
  componentDidMount = () => {
    portalRoot.appendChild(this.el);
  };

  // 如果组件从DOM中移除,那么我们也将其子元素移除
  componentWillUnmount = () => {
    portalRoot.removeChild(this.el);
  };

  // 啊,现在我们可以根据需要渲染组件及其子元素
  render() {
    const { children } = this.props;
    return ReactDOM.createPortal(children, this.el);
  }
}
登录后复制

当然,render()可以渲染数字和字符串……

class App extends React.Component {
  render () {
    return "Hello World!"
  }
}
登录后复制

以及null或布尔值:

class App extends React.Component {
  render () {
    return null
  }
}
登录后复制

componentDidMount()

componentDidMount()这个名字是否说明了它的含义?此方法在组件挂载(即连接到DOM)后调用。在我撰写的另一篇关于在React中获取数据的教程中,这就是您要向API发出请求以获取数据的地方。

我们可以使用您的fetch方法:

fetchUsers() {
  fetch(`https://jsonplaceholder.typicode.com/users`)
    .then(response => response.json())
    .then(data =>
      this.setState({
        users: data,
        isLoading: false,
      })
    )
  .catch(error => this.setState({ error, isLoading: false }));
}
登录后复制

然后在componentDidMount()钩子中调用该方法:

componentDidMount() {
  this.fetchUsers();
}
登录后复制

我们还可以添加事件监听器:

componentDidMount() {
  el.addEventListener()
}
登录后复制

很简洁,对吧?

static getDerivedStateFromProps()

这是一个有点冗长的名字,但static getDerivedStateFromProps()并不像听起来那么复杂。它在挂载阶段的render()方法之前以及更新阶段之前调用。它返回一个对象来更新组件的状态,或者在没有要更新的内容时返回null

为了理解它的工作原理,让我们实现一个计数器组件,它将为其计数器状态设置一个特定值。只有当maxCount的值更高时,此状态才会更新。maxCount将从父组件传递。

这是父组件:

class App extends React.Component {
  constructor(props) {
    super(props)

    this.textInput = React.createRef();
    this.state = {
      value: 0
    }
  }

  handleIncrement = e => {
    e.preventDefault();
    this.setState({ value: this.state.value   1 })
  };

  handleDecrement = e => {
    e.preventDefault();
    this.setState({ value: this.state.value - 1 })
  };

  render() {
    return (
      <react.fragment><p>Max count: { this.state.value }</p>
           
          -
        <counter maxcount="{this.state.value}"></counter></react.fragment>
    )
  }
}
登录后复制

我们有一个按钮用于增加maxCount的值,我们将其传递给Counter组件。

class Counter extends React.Component {
  state={
    counter: 5
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.counter 
        <p>Count: {this.state.counter}</p>

      
    )
  }
}
登录后复制

Counter组件中,我们检查counter是否小于maxCount。如果是,我们将counter设置为maxCount的值。否则,我们什么也不做。

更新阶段

当组件的props或状态更改时,会发生更新阶段。与挂载一样,更新也有自己的一组可用方法,我们接下来将介绍。也就是说,值得注意的是,render()getDerivedStateFromProps()也会在此阶段触发。

shouldComponentUpdate()

当组件的状态或props更改时,我们可以使用shouldComponentUpdate()方法来控制组件是否应该更新。此方法在渲染发生之前以及接收状态和props时调用。默认行为为true。要每次状态或props更改时都重新渲染,我们会这样做:

shouldComponentUpdate(nextProps, nextState) {
  return this.state.value !== nextState.value;
}
登录后复制

当返回false时,组件不会更新,而是调用render()方法来显示组件。

getSnapshotBeforeUpdate()

我们可以做的一件事是在某个时间点捕获组件的状态,这就是getSnapshotBeforeUpdate()的设计目的。它在render()之后但提交任何新更改到DOM之前调用。返回值作为第三个参数传递给componentDidUpdate()

它将先前状态和props作为参数:

getSnapshotBeforeUpdate(prevProps, prevState) {
  // ...
}
登录后复制

在我看来,此方法的用例很少。它是一种您可能不会经常使用到的生命周期方法。

componentDidUpdate()

componentDidUpdate()添加到方法列表中,其中名称大致说明了所有内容。如果组件更新,那么我们可以使用此方法在此时与它挂钩,并将其传递给组件的先前props和状态。

componentDidUpdate(prevProps, prevState) {
  if (prevState.counter !== this.state.counter) {
    // ...
  }
}
登录后复制

如果您曾经使用过getSnapshotBeforeUpdate(),您还可以将返回值作为参数传递给componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot) {
  if (prevState.counter !== this.state.counter) {
    // ....
  }
}
登录后复制

卸载阶段

我们在这里几乎看到了挂载阶段的反面。正如您可能预期的那样,卸载发生在组件从DOM中清除并且不再可用时。

我们这里只有一个方法:componentWillUnmount()

这在组件卸载和销毁之前调用。这就是我们想要在组件离开后执行任何必要的清理的地方,例如删除可能在componentDidMount()中添加的事件监听器,或清除订阅。

// 删除事件监听器
componentWillUnmount() {
  el.removeEventListener()
}
登录后复制

错误处理阶段

组件中可能会出现问题,这可能会导致错误。我们已经有一段时间使用错误边界来帮助解决这个问题。此错误边界组件使用一些方法来帮助我们处理可能遇到的错误。

getDerivedStateFromError()

我们使用getDerivedStateFromError()来捕获从子组件抛出的任何错误,然后我们使用它来更新组件的状态。

class ErrorBoundary extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      hasError: false
    };
  }

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

  render() {
    if (this.state.hasError) {
      return (
        <h1 id="Oops-something-went-wrong">Oops, something went wrong :(</h1>
      );
    }

    return this.props.children;
  }
}
登录后复制

在此示例中,当从子组件抛出错误时,ErrorBoundary组件将显示“哎呀,出现了一些问题”。

componentDidCatch()

虽然getDerivedStateFromError()适用于在发生副作用(如错误日志记录)的情况下更新组件的状态,但我们应该使用componentDidCatch(),因为它在提交阶段调用,此时DOM已更新。

componentDidCatch(error, info) {
  // 将错误记录到服务
}
登录后复制

getDerivedStateFromError()componentDidCatch()都可以在ErrorBoundary组件中使用:

class ErrorBoundary extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      hasError: false
    };
  }

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

  componentDidCatch(error, info) {
    // 将错误记录到服务
  }

  render() {
    if (this.state.hasError) {
      return (
        <h1 id="Oops-something-went-wrong">Oops, something went wrong :(</h1>
      );
    }

    return this.props.children;
  }
}
登录后复制

这就是React组件的生命周期!

了解React组件如何与DOM交互是一件很酷的事情。很容易认为会发生一些“魔法”,然后页面上就会出现一些东西。但是React组件的生命周期表明,这种疯狂是有秩序的,它旨在赋予我们很大的控制权,以便从组件到达DOM到它消失的时间发生的事情。

我们在相对较短的空间内涵盖了很多内容,但希望这能让您很好地了解React如何处理组件,以及我们在处理的各个阶段拥有什么样的能力。如果您对这里介绍的任何内容不清楚,请随时提出任何问题,我很乐意尽力提供帮助!

以上是反应生命周期的圆的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

带有粘性定位的堆叠卡和一点点的杂物 带有粘性定位的堆叠卡和一点点的杂物 Apr 03, 2025 am 10:30 AM

前几天,我发现了科里·金尼文(Corey Ginnivan)网站上的这一点,当您滚动时,彼此之间的卡片堆放集。

Google字体可变字体 Google字体可变字体 Apr 09, 2025 am 10:42 AM

我看到Google字体推出了新设计(Tweet)。与上一次大型重新设计相比,这感觉更加迭代。我几乎无法分辨出区别

如何使用HTML,CSS和JavaScript创建动画倒计时计时器 如何使用HTML,CSS和JavaScript创建动画倒计时计时器 Apr 11, 2025 am 11:29 AM

您是否曾经在项目上需要一个倒计时计时器?对于这样的东西,可以自然访问插件,但实际上更多

为什么Flex布局中的紫色斜线区域会被误认为是'溢出空间”? 为什么Flex布局中的紫色斜线区域会被误认为是'溢出空间”? Apr 05, 2025 pm 05:51 PM

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...

如何通过CSS选择第一个类名为item的子元素? 如何通过CSS选择第一个类名为item的子元素? Apr 05, 2025 pm 11:24 PM

在元素个数不固定的情况下如何通过CSS选择第一个指定类名的子元素在处理HTML结构时,常常会遇到元素个数不�...

HTML数据属性指南 HTML数据属性指南 Apr 11, 2025 am 11:50 AM

您想了解的有关HTML,CSS和JavaScript中数据属性的所有信息。

使Sass更快的概念证明 使Sass更快的概念证明 Apr 16, 2025 am 10:38 AM

在一个新项目开始时,Sass汇编发生在眼睛的眨眼中。感觉很棒,尤其是当它与browsersync配对时,它重新加载

在前端开发中,如何使用CSS和JavaScript实现类似Windows 10设置界面的探照灯效果? 在前端开发中,如何使用CSS和JavaScript实现类似Windows 10设置界面的探照灯效果? Apr 05, 2025 pm 10:21 PM

在前端开发中如何实现类似Windows...

See all articles