掛載階段的組件生命週期(二)

這一節咱們來討論一下對於一個組件來講,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 來說。

相關文章
相關標籤/搜索