挂载阶段的组件生命周期(二)

这一节咱们来讨论一下对于一个组件来讲,constructor 、componentWillMountcomponentDidMountcomponentWillUnmount 这几个方法在一个组件的出生到死亡的过程里面起了什么样的做用。html

通常来讲,全部关于组件自身的状态的初始化工做都会放在 constructor 里面去作。你会发现本书全部组件的 state 的初始化工做都是放在 constructor 里面的。假设咱们如今在作一个时钟应用:ajax

咱们会在 constructor 里面初始化 state.date,固然如今页面仍是静态的,等下一会让时间动起来。json

class Clock extends Component {
  constructor () {
    super()
    this.state = {
      date: new Date()
    }
  }

  render () {
    return (
      <div>
        <h1>
          <p>如今的时间是</p>
          {this.state.date.toLocaleTimeString()}
        </h1>
      </div>
    )
  }
}

一些组件启动的动做,包括像 Ajax 数据的拉取操做、一些定时器的启动等,就能够放在 componentWillMount 里面进行,例如 Ajax:api

...
  componentWillMount () {
    ajax.get('http://json-api.com/user', (userData) => {
      this.setState({ userData })
    })
  }
...

固然在咱们这个例子里面是定时器的启动,咱们给 Clock 启动定时器:闭包

class Clock extends Component {
  constructor () {
    super()
    this.state = {
      date: new Date()
    }
  }

  componentWillMount () {
    this.timer = setInterval(() => {
      this.setState({ date: new Date() })
    }, 1000)
  }
  ...
}

咱们在 componentWillMount 中用 setInterval 启动了一个定时器:每隔 1 秒更新中的 state.date,这样页面就能够动起来了。咱们用一个 Index 把它用起来,而且插入页面:ide

class Index extends Component {
  render () {
    return (
      <div>
        <Clock />
      </div>
    )
  }
}

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

像上一节那样,咱们修改这个 Index 让这个时钟能够隐藏或者显示:函数

class Index extends Component {
  constructor () {
    super()
    this.state = { isShowClock: true }
  }

  handleShowOrHide () {
    this.setState({
      isShowClock: !this.state.isShowClock
    })
  }

  render () {
    return (
      <div>
        {this.state.isShowClock ? <Clock /> : null }
        <button onClick={this.handleShowOrHide.bind(this)}>
          显示或隐藏时钟
        </button>
      </div>
    )
  }
}

如今页面上有个按钮能够显示或者隐藏时钟。你试一下显示或者隐藏时钟,虽然页面上看起来功能都正常,在控制台你会发现报错了:动画

这是由于,当时钟隐藏的时候,咱们并无清除定时器。时钟隐藏的时候,定时器的回调函数还在不停地尝试 setState,因为 setState 只能在已经挂载或者正在挂载的组件上调用,因此 React.js 开始疯狂报错。this

屡次的隐藏和显示会让 React.js 从新构造和销毁 Clock 组件,每次构造都会从新构建一个定时器。而销毁组件的时候没有清除定时器,因此你看到报错会愈来愈多。并且由于 JavaScript 的闭包特性,这样会致使严重的内存泄漏。spa

这时候componentWillUnmount 就能够派上用场了,它的做用就是在组件销毁的时候,作这种清场的工做。例如清除该组件的定时器和其余的数据清理工做。咱们给 Clock添加 componentWillUnmount,在组件销毁的时候清除该组件的定时器:

...
  componentWillUnmount () {
    clearInterval(this.timer)
  }
...

这时候就没有错误了。

总结

咱们通常会把组件的 state 的初始化工做放在 constructor 里面去作;在 componentWillMount 进行组件的启动工做,例如 Ajax 数据拉取、定时器的启动;组件从页面上销毁的时候,有时候须要一些数据的清理,例如定时器的清理,就会放在 componentWillUnmount 里面去作。

说一下本节没有提到的 componentDidMount 。通常来讲,有些组件的启动工做是依赖 DOM 的,例如动画的启动,而 componentWillMount 的时候组件还没挂载完成,因此无法进行这些启动工做,这时候就能够把这些操做放在 componentDidMount 当中。componentDidMount 的具体使用咱们会在接下来的章节当中结合 DOM 来说。

相关文章
相关标签/搜索