iT邦幫忙

2021 iThome 鐵人賽

DAY 23
1
自我挑戰組

Re: 從 Next.js 開始的 React 生活系列 第 23

[Day23] 在 Codecademy 學 React ~ Component Lifecycle 生命週期我不懂你QQ

  • 分享至 

  • xImage
  •  

前言

原本以為生命週期應該很好懂,
但我卡在別的地方,
不過快 12 點了啊我先 po 出我目前進度QQ
The Component Lifecycle

本日正文

https://ithelp.ithome.com.tw/upload/images/20210925/20129873bNKhtaPuYC.png
在這個章節 Codecademy 會不斷提到 component lifecycle 分成三個最高的階段:

  1. Mounting:當 component initial 並放到 DOM 上
  2. Updating:當 component 的 props, state 有所改變時
  3. 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);

setInterval

這樣看起來似乎沒有問題了,
但你發現時間好像不會跟著變化,
只會停在渲染網頁當下的時間,對吧?

這邊 Codecademy 告訴你可以使用 setInterval 做到計時的效果
(setInterval 大家應該不陌生,就是每隔一段時間就要執行一次 function)

但問題來了,setInterval 該放在哪裡?

在這個章節 Codecademy 會不斷提到 component lifecycle 分成三個最高的階段:

  1. Mounting:當 component initial 並放到 DOM 上
  2. Updating:當 component 的 props, state 有所改變時
  3. Unmounting:當 component 從 DOM 上被移除

再讓我們回想一下 lifecycle 的階段,
這邊你一定可以肯定絕對不會是把 setInterval 放在 Unmounting 階段執行,
再來到目前為止我們最常使用的兩個生命週期 function: render, constructor
這兩個適合放嗎?
constructor 顯然不適合,因為只會在 component 被 mount 時執行一次。
render 呢?render 會在 mounting phase 及 updating phase 都被執行,
這樣太過頻繁了,
也不適合。

componentDidMount

這邊 Codecademy 教了一個新的方法:componentDidMount()
順序是這樣的:

  1. The constructor
  2. render()
  3. componentDidMount()

https://ithelp.ithome.com.tw/upload/images/20210925/20129873huVmjMMxod.png

所以 componentDidMount 當 component 被渲染(render)之後才會執行,
而我們這邊就試著把 setInterval 放在 componentDidMount 中間,
像這樣:

componentDidMount() {
    const oneSecond = 1000;
    this.intervalID = setInterval(() => {
      this.setState({ date: new Date() });
    }, oneSecond);
  }

componentWillUnmount

看起來也有在運作了,
然後有 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


上一篇
[Day22] 在 Codecademy 學 React ~ 原來 useState 就是 this.state + this.setState 啊!
下一篇
[Day24] 在 Codecademy 學 React ~ 終於來到 Hook 的世界 ‧ useState 篇 (1)
系列文
Re: 從 Next.js 開始的 React 生活31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言