React.js 小書 Lesson19 - 掛載階段的組件生命周期(二)
轉載請注明出處,保留原文鏈接以及作者信息
在線閱讀:http://huziketang.com/books/react
這一節我們來討論一下對于一個組件來說,constructor
、componentWillMount
、componentDidMount
、componentWillUnmount
這幾個方法在一個組件的出生到死亡的過程里面起了什么樣的作用。
一般來說,所有關于組件自身的狀態的初始化工作都會放在 constructor
里面去做。你會發現本書所有組件的 state
的初始化工作都是放在 constructor
里面的。假設我們現在在做一個時鐘應用:
[圖片上傳失敗...(image-a4f288-1510226804313)]
我們會在 constructor
里面初始化 state.date
,當然現在頁面還是靜態的,等下一會讓時間動起來。
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:
...
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
把它用起來,并且插入頁面:
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>
)
}
}
現在頁面上有個按鈕可以顯示或者隱藏時鐘。你試一下顯示或者隱藏時鐘,雖然頁面上看起來功能都正常,在控制臺你會發現報錯了:
[圖片上傳失敗...(image-52428a-1510226804314)]
這是因為,當時鐘隱藏的時候,我們并沒有清除定時器。時鐘隱藏的時候,定時器的回調函數還在不停地嘗試 setState
,由于 setState
只能在已經掛載或者正在掛載的組件上調用,所以 React.js 開始瘋狂報錯。
多次的隱藏和顯示會讓 React.js 重新構造和銷毀 Clock
組件,每次構造都會重新構建一個定時器。而銷毀組件的時候沒有清除定時器,所以你看到報錯會越來越多。而且因為 JavaScript 的閉包特性,這樣會導致嚴重的內存泄漏。
這時候componentWillUnmount
就可以派上用場了,它的作用就是在組件銷毀的時候,做這種清場的工作。例如清除該組件的定時器和其他的數據清理工作。我們給 Clock
添加 componentWillUnmount
,在組件銷毀的時候清除該組件的定時器:
...
componentWillUnmount () {
clearInterval(this.timer)
}
...
這時候就沒有錯誤了。
總結
我們一般會把組件的 state
的初始化工作放在 constructor
里面去做;在 componentWillMount
進行組件的啟動工作,例如 Ajax 數據拉取、定時器的啟動;組件從頁面上銷毀的時候,有時候需要一些數據的清理,例如定時器的清理,就會放在 componentWillUnmount
里面去做。
說一下本節沒有提到的 componentDidMount
。一般來說,有些組件的啟動工作是依賴 DOM 的,例如動畫的啟動,而 componentWillMount
的時候組件還沒掛載完成,所以沒法進行這些啟動工作,這時候就可以把這些操作放在 componentDidMount
當中。componentDidMount
的具體使用我們會在接下來的章節當中結合 DOM 來講。
下一節中我們將介紹《React.js 小書 Lesson20 - 更新階段的組件生命周期》。