掌握React生命周期方法

总览

React组件封装了部分UI。 完整的React应用程序UI呈现为许多嵌套组件的树。 根据应用程序的流程,各个组件需要在渲染之前和之后以及更新之前和之后执行一些任务。

最后,清理和错误处理也很重要。 React提供了许多生命周期方法,您可以覆盖它们并将它们自己的逻辑插入正确的位置。 在本教程中,您将了解从摇篮到坟墓的React组件的生命周期,每个阶段可用的方法以及何时覆盖它们。

请注意,在本教程中,我使用现代的ES6类样式。

PopularBar

我将使用一个名为PopularBar的组件来说明所有生命周期方法及其行为。 完整的源代码可在GitLab上获得

流行的栏包含另外两个称为ClickCounter组件。 每个ClickCounter组件都包含一个带有表情符号的按钮,并显示其被添加到从其主机接收的count属性中被单击的次数。 这是ClickCounterrender()方法:

render() {
    return (
      <span className='padded'
            onClick={() => {
              let clickCount = this.state.clickCount + 1
              this.setState({clickCount: clickCount})
            }}
      >
        <button>{this.props.emoji}</button>
        {this.getTotal() < 100 ? this.getTotal() : "99+"}
      </span>
    );
  }

PopularBar组件呈现两个ClickCounter组件,它们带有大拇指和大拇指表情符号。 请注意,如果“ show”道具为false,它将呈现一个空的div。 稍后在讨论安装和卸载时,这一点很重要。

render() {
    if (!this.props.show) {
      return (<div />)
    }

    return (
        <div className="padded" style={this.props.style}>
          <ClickCounter
            emoji={thumbsup}
            count={this.props.upCount}
          />
          <ClickCounter
            emoji={thumbsdown}
            count={this.props.downCount}
          />
        </div>
    )
  }
Popular Bar的第一次迭代

安装

当组件由父组件或根应用程序呈现时,它们便存在。 但是在呈现组件之前,需要将其构造(仅一次)并安装到虚拟DOM中(每次将其添加到虚拟DOM中)。

事件的顺序是,首先构造组件,然后调用componentWillMount()方法,将组件安装到虚拟DOM中,然后是componentDidMount() 叫做。 这为您提供了执行不同类型的初始化的大量机会。

建设者

组件的构造函数将在每个应用程序中调用一次(如果您在浏览器中刷新页面,则该页面将被视为新应用程序)。 这是PopularBar组件的构造函数。 除了调用super()并登录到控制台外,它实际上什么也没做。

class PopularBar extends Component {
  constructor() {
    super()
    console.log('--- PopularBar constructor is here!')
  }

ClickCounter的构造函数将其clickCount状态初始化为零:

class ClickCounter extends Component {
  constructor(props) {
    super(props)
    this.state = {
      clickCount: 0
    }

    console.log(props.emoji + 
                '=== ClickCounter constructor is here!')
  }

这是初始化的完美示例,每个应用程序必须进行一次初始化。 如果ClickCounter组件已多次安装,则应保留其点击计数。

ComponentWillMount

componentWillMount()安装之前将调用componentWillMount()方法,因此尚无组件。 通常,在此阶段没有太多的事情可以做,除非每次安装组件时都会进行一些特殊的初始化,但是即使初始化也可以等待componentDidMount() 方法。

以下是PopularBar和ClickCounter的方法实现:

// PopularBar 
  componentWillMount() {
    console.log('--- PopularBar will mount. Yay!')
  }


  // ClickCounter
  componentWillMount() {
    console.log(this.props.emoji + 
                '=== ClickCounter will mount. Yay!')
  }

如果需要,可以在这里调用this.setState() 。 道具显然无法使用。

ComponentDidMount

在这里,该组件已经安装好,您可以在虚拟DOM的上下文中执行需要访问该组件的任何工作。 这是PopularBar和ClickCounter的方法实现。 该组件已经存在,因此可以访问和显示其属性(属性)。

componentDidMount() {
    console.log('--- PopularBar did mount. upCount: ' + 
                 this.props.upCount + ', downCount: ' +
                 this.props.downCount)
  }


  // ClickCounter
  componentDidMount() {
    console.log(this.props.emoji + 
                '=== ClickCounter did mount. count: ' +      
                this.props.count)
  }

总结安装部分,让我们看一下PopularBar及其包含的两个ClickCounter组件的事件顺序。 为了方便起见,我为每个ClickCounter显示了表情符号,以便区分它们。

--- PopularBar constructor is here!
--- PopularBar will mount. Yay!
👍=== ClickCounter constructor is here!
👍=== ClickCounter will mount. Yay!
👎=== ClickCounter constructor is here!
👎=== ClickCounter will mount. Yay!
👍=== ClickCounter did mount. count: 5
👎=== ClickCounter did mount. count: 8
--- PopularBar did mount. upCount: 5, downCount: 8

首先,构造PopularBar并调用其componentWillMount()方法。 然后,调用每个ClickCounter组件的构造方法和componentWillMount()方法,然后调用两个ClickCounter组件的componentDidMount() 。 最后,将调用PopularBar的componentDidMount()方法。 总的来说,流程是嵌套的,其中所有子组件必须完全安装,然后才能完全包含其子组件。

更新中

一旦安装了组件,就可以渲染它。 组件或从容器中接收的道具的状态可能时不时地发生变化。 这些更改导致重新渲染,但是组件有机会得到通知,甚至可以控制是否应该进行渲染。

更新过程涉及四种方法,我将按顺序介绍它们。

ComponentWillReceiveProps

从容器接收到新的道具时,将调用componentWillReceiveProps()方法。 您可以通过this.props访问当前道具,并通过nextProps参数访问下一个道具。 这是ClickCounter的componentWillReceiveProps()方法。

componentWillReceiveProps(nextProps) {
    console.log(this.props.emoji + 
                '=== ClickCounter will receive props. ' + 
                'next props: ' + nextProps.count)
  }

您有机会在这里检查哪些道具已更改,并根据需要修改组件的状态。 可以在这里调用this.setState()

应该组件更新

shouldComponentUpdate()是一个关键方法。 当接收到新的道具时(在componentWillReceiveProps()调用之后),或者在其他地方修改了组件的状态后,将调用该方法。 如果您未实现此方法,则组件将每次重新渲染。

但是,如果实现它并返回“ false”,则将不呈现该组件及其子组件。 请注意,如果子组件的状态被修改,即使您总是从父组件的shouldComponentUpdate()返回“ false”,它们也将被重新渲染。

您可以在此处访问下一个道具和下一个状态,因此您拥有决策所需的所有信息。 当ClickCounter组件的计数超过99时,它将显示99+,因此仅当计数小于100时才需要更新。这是代码:

shouldComponentUpdate(nextProps, nextState) {
    let currTotal = this.getTotal()
    let shouldUpdate = currTotal < 100

    console.log(this.props.emoji + '=== ClickCounter should ' +
                (shouldUpdate ? '' : 'NOT ') + 'update')
    return shouldUpdate
  }

ComponentWillUpdate

componentWillUpdateMethod()在组件后称为shouldComponentUpdate()只有shouldComponentUpdate()返回真。 此时,您将拥有下一个道具和下一个状态。 您无法在此处修改状态,因为它将导致shouldComponentUpdate()再次被调用。

这是代码:

componentWillUpdate(nextProps, nextState) {
    console.log(this.props.emoji + 
                '=== ClickCounter will update' +
                ' nextProps.count: ' + nextProps.count +
                ' nextState.clickCount: ' + nextState.clickCount)
  }

ComponentDidUpdate

最后,在渲染之后,调用componentDidUpdate()方法。 可以在此处调用this.setState()是因为先前状态更改的渲染已经完成。

这是代码:

componentDidUpdate() {
    console.log(this.props.emoji + '=== ClickCounter did update')
  }

让我们看看实际的更新方法。 我将导致两种类型的更新。 首先,我将点击大拇指按钮以触发状态更改:

--- PopularBar constructor is here!  PopularBar.js:10
--- PopularBar will mount. Yay!  PopularBar.js:14
👍=== ClickCounter constructor is here!
👍=== ClickCounter will mount. Yay!
👎=== ClickCounter constructor is here!
👎=== ClickCounter will mount. Yay!
👍=== ClickCounter did mount. count: 5  ClickCounter.js:20
👎=== ClickCounter did mount. count: 8  ClickCounter.js:20
--- PopularBar did mount. upCount: 5, downCount: 8 
👍=== ClickCounter should update
👍=== ClickCounter will update nextProps.count: 5 
                               nextState.clickCount: 1  
👍=== ClickCounter did update

请注意, nextState.clickCount为1,这将触发更新周期。 下次更新将由父级传递新道具引起。 为了实现这一点,我将添加一个小功能,该功能每5秒触发一次,并将计数增加20。这是包含PopularBar的主App组件中的代码。 更改将一直传播到ClickCounter。

class App extends Component {
  constructor() {
    super()
    this.state = {
      showPopularBar: true,
      upCount: 5,
      downCount: 8
    }
  }

  componentDidMount() {
    this.timer = setInterval(this.everyFiveSeconds.bind(this), 
                             5000);
  }

  everyFiveSeconds() {
    let state = this.state
    state.upCount += 20
    this.setState(state)
  }

这是输出。 请注意,已经调用了ClickCounter willReceiveProps()方法,并且nextState.clickCount保持为零,但是nextProps.Count现在为25。

--- PopularBar constructor is here!
--- PopularBar will mount. Yay!
👍=== ClickCounter constructor is here!
👍=== ClickCounter will mount. Yay!
👎=== ClickCounter constructor is here!
👎=== ClickCounter will mount. Yay!
👍=== ClickCounter did mount. count: 5
👎=== ClickCounter did mount. count: 8
--- PopularBar did mount. upCount: 5, downCount: 8
👍=== ClickCounter will receive props. next props:25
👍=== ClickCounter should update
👍=== ClickCounter will update nextProps.count: 25 
                               nextState.clickCount: 0

卸载和错误处理

可以卸载并重新安装组件,并且在组件的生命周期中可能会出现错误。

组件将卸下

如果组件未由其容器呈现,则将其从虚拟DOM卸载,然后调用已卸载组件的componentWillUnmount()方法。 如果show prop为false,PopularBar将不会呈现其ClickCounter子组件。 App组件将渲染PopularBar并根据复选框传递show prop。

这是应用程序的render()方法:

render() {
    return (
      <div>
        <h1>Popular Bar</h1>
        <label>
          <input
            type='checkbox'
            defaultChecked={this.state.showPopularBar}
            ref='showPopularBar'
            onChange={() => this.setState(
                 {showPopularBar: !this.state.showPopularBar})
            }
          />
          Show popular bar
        </label>

        <PopularBar
            show={this.state.showPopularBar}
            upCount={this.state.upCount}
            downCount={this.state.downCount}
        />
      </div>
    )
  }

当用户取消选中该复选框时,仍然会渲染PopularBar,但不会渲染其子组件,这些子组件将被卸载。 这是代码和输出:

componentWillUnmount() {
    console.log(this.props.emoji + 
                '=== ClickCounter will unmount :-(')
  }


Output:

👍=== ClickCounter will unmount :-(  
👎=== ClickCounter will unmount :-(

因为目前没有组件,所以没有componentDidUnmount()方法。

ComponentDidCatch

在React 16中最近添加了componentDidCatch()方法。该方法旨在帮助解决渲染期间以前导致晦涩的错误消息的错误。 现在,可以定义特殊的错误边界组件,该组件包装可能引发错误的任何子组件,并且仅在发生错误时才呈现错误边界组件。

结论

React组件具有明确定义的生命周期,而特殊的方法可让您插入逻辑并采取措施,以非常细粒度的级别控制状态,甚至处理错误。

在大多数情况下,这不是必需的,您可以传递道具并实现render()方法,但是很高兴知道,在更特殊的情况下,您不会盯着黑匣子。

在过去的几年中,React越来越受欢迎。 实际上,我们在市场上有许多商品可供购买,查看,实施等。 如果您正在寻找有关React的其他资源,请随时检查

翻译自: https://code.tutsplus.com/tutorials/mastering-the-react-lifecycle-methods--cms-29849

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值