原本以為生命週期應該很好懂,
但我卡在別的地方,
不過快 12 點了啊我先 po 出我目前進度QQ
The Component Lifecycle
在這個章節 Codecademy 會不斷提到 component lifecycle 分成三個最高的階段:
- Mounting:當 component initial 並放到 DOM 上
- Updating:當 component 的 props, state 有所改變時
- Unmounting:當 component 從 DOM 上被移除
而這邊用了一個即時時間顯示的例子來帶入各個生命週期的教學。
首先我們一樣先新增一個 Clock.js,
裡面我先擺一個時間顯示,
時間顯示擺在一個 <div>
中:
<div>{這邊預計要擺時間}</div>
但我們當然想要讀取當下的時間,
所以我們要在 constructor 宣告一個 state 為 date,
值設定為 new Date()
,
像這樣:
constructor(props) {
super(props);
this.state = {
date: new Date(),
};
}
有了這個宣告之後,
我就可以回過頭去改 <div>
裡面的值了,
改成這樣:
<div>{this.state.date.toLocaleTimeString()}</div>
(PS. toLocaleTimeString 的作用是轉成所在時區的時間)
而按鈕最單純先擺這樣:
<button>隱藏時間</button>
可是我想要讓按鈕點了有顯示時間、隱藏時間的功用,
該怎麼做?
在 constructor 中,
除了 date 的宣告之外,
還要再多宣告一個 toggleClock,
拿來控制時間的開關,
像這樣:
constructor(props) {
super(props);
this.state = {
date: new Date(),
toggleClock: true
};
}
再來就是宣告一個 function,
當 toggleClock 是 true 就改為 false,
反之就改成 true,
像這樣:
changeClock() {
this.setState({ toggleClock: !this.state.toggleClock });
}
再來就是到按鈕的地方設定 onClick 事件時要執行 changeClock 的 function,
還有按鈕的文字也要根據 toggleClock 是 true 或 false 而要有所變化,
像這樣:
<button onClick={this.changeClock}>
{this.state.toggleClock ? "隱藏時間" : "顯示時間"}
</button>
可是這時候當你點擊按鈕卻出現 error,
這邊不要忘了宣告一個 function 後,
在 constructor 要讓它 bind this:
this.changeClock = this.changeClock.bind(this);
這樣看起來似乎沒有問題了,
但你發現時間好像不會跟著變化,
只會停在渲染網頁當下的時間,對吧?
這邊 Codecademy 告訴你可以使用 setInterval
做到計時的效果
(setInterval
大家應該不陌生,就是每隔一段時間就要執行一次 function)
但問題來了,setInterval
該放在哪裡?
在這個章節 Codecademy 會不斷提到 component lifecycle 分成三個最高的階段:
- Mounting:當 component initial 並放到 DOM 上
- Updating:當 component 的 props, state 有所改變時
- Unmounting:當 component 從 DOM 上被移除
再讓我們回想一下 lifecycle 的階段,
這邊你一定可以肯定絕對不會是把 setInterval 放在 Unmounting 階段執行,
再來到目前為止我們最常使用的兩個生命週期 function: render, constructor
這兩個適合放嗎?
constructor 顯然不適合,因為只會在 component 被 mount 時執行一次。
render 呢?render 會在 mounting phase 及 updating phase 都被執行,
這樣太過頻繁了,
也不適合。
這邊 Codecademy 教了一個新的方法:componentDidMount()
順序是這樣的:
- The constructor
- render()
- componentDidMount()
所以 componentDidMount 當 component 被渲染(render)之後才會執行,
而我們這邊就試著把 setInterval 放在 componentDidMount 中間,
像這樣:
componentDidMount() {
const oneSecond = 1000;
this.intervalID = setInterval(() => {
this.setState({ date: new Date() });
}, oneSecond);
}
看起來也有在運作了,
然後有 mount 當然也有 unmount,
但這個時間被隱藏起來的時候你當然也會希望這個計時器可以暫停,
避免在背後吃掉資源對吧?
所以 Codecademy 在這時候教了 componentWillUnmount,
意思是在 component unmount 時要執行的動作,
像這樣:
componentWillUnmount() {
clearInterval(this.intervalID);
}![](http://)
但為了驗證是不是真的有停下來我有故意在 componentDidMount 埋了 console.log 來看,
componentDidMount() {
const oneSecond = 1000;
this.intervalID = setInterval(() => {
this.setState({ date: new Date() });
console.log("時鐘還在跑哦");
}, oneSecond);
}
結果發現隱藏時間後 console.log 還在執行,
表示沒有停止計時=口=
我剛花很多時間在找停止計時不 work 的原因,
但目前還不確定問題是出在 component 沒有 unmount 還是 this.intervalID 之類的,
但因為快 12 點了,
只好先停止 trouble shooting 了,
我先來 po 文orz
然後附上本日程式→ Day23 - Lifecycle (Codecademy)
希望我明天找得出原因QQ