搜索
首页web前端css教程反应生命周期的圆

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
光标的下一个CSS样式光标的下一个CSS样式Apr 23, 2025 am 11:04 AM

具有CSS的自定义光标很棒,但是我们可以将JavaScript提升到一个新的水平。使用JavaScript,我们可以在光标状态之间过渡,将动态文本放置在光标中,应用复杂的动画并应用过滤器。

世界碰撞:使用样式查询的钥匙帧碰撞检测世界碰撞:使用样式查询的钥匙帧碰撞检测Apr 23, 2025 am 10:42 AM

互动CSS动画和元素相互启动的元素在2025年似乎更合理。虽然不需要在CSS中实施乒乓球,但CSS的灵活性和力量的增加,可以怀疑Lee&Aver Lee&Aver Lee有一天将是一场

使用CSS背景过滤器进行UI效果使用CSS背景过滤器进行UI效果Apr 23, 2025 am 10:20 AM

有关利用CSS背景滤波器属性来样式用户界面的提示和技巧。您将学习如何在多个元素之间进行背景过滤器,并将它们与其他CSS图形效果集成在一起以创建精心设计的设计。

微笑吗?微笑吗?Apr 23, 2025 am 09:57 AM

好吧,事实证明,SVG的内置动画功能从未按计划进行弃用。当然,CSS和JavaScript具有承载负载的能力,但是很高兴知道Smil并没有像以前那样死在水中

'漂亮”在情人眼中'漂亮”在情人眼中Apr 23, 2025 am 09:40 AM

是的,让#039;跳上文字包装:Safari Technology Preview In Pretty Landing!但是请注意,它与在铬浏览器中的工作方式不同。

CSS-tricks编年史XLIIICSS-tricks编年史XLIIIApr 23, 2025 am 09:35 AM

此CSS-tricks更新了,重点介绍了年鉴,最近的播客出现,新的CSS计数器指南以及增加了几位新作者,这些新作者贡献了有价值的内容。

tailwind的@Apply功能比听起来更好tailwind的@Apply功能比听起来更好Apr 23, 2025 am 09:23 AM

在大多数情况下,人们展示了@Apply的@Apply功能,其中包括Tailwind的单个property实用程序之一(会改变单个CSS声明)。当以这种方式展示时,@Apply听起来似乎很有希望。如此明显

感觉就像我没有释放:走向理智的旅程感觉就像我没有释放:走向理智的旅程Apr 23, 2025 am 09:19 AM

像白痴一样部署的部署归结为您部署的工具与降低复杂性与添加的复杂性之间的奖励之间的不匹配。

See all articles

热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

好用且免费的代码编辑器

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

禅工作室 13.0.1

禅工作室 13.0.1

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

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具