[官網學 React] Docs:State 和生命週期

Juju 的自學筆記
7 min readApr 26, 2021

--

網址(英文):https://reactjs.org/docs/components-and-props.html
網址(中文):https://zh-hant.reactjs.org/docs/state-and-lifecycle.html

這篇介紹在 React component 的 state 和生命週期。

之前在 Rendering Elements 渲染元素 那篇時,我們只會運用呼叫 ReactDOM.render() 做渲染,如以下例子:

ticking clock

上面例子透過每一秒呼叫一次 setInterval() callback,讓 ReactDOM.render() 能一秒重新渲染一次。

這篇官網會教我們如何使這個時鐘元件能被重複使用和封裝,它將會設定自己的 timer 並每秒更新一次。

封裝 Clock Component

但目前還是得依賴 setInterval() 才能做到畫面每秒渲染一次。

我們的目標是 Clock 組件建立一個計時器後,能每秒自動更新 UI,最後能寫成以下這樣:

要能做到這樣,需要在 Clock 元件新增 state。

state 類似 props,差異是 state 是 component 能完全掌控的,且是非公開的(private)。

將 Function 轉換成 class

將 Clock 物件從 function component 轉成 class component 五步驟:

  1. 建立一個名稱也是 Clock 的 ES6 class,繼承 React.Component
  2. 新增一個空函式 render()
  3. 將原本 function component 的全部內容搬進 render()
  4. render() 的 body 裡用 this.props 取代 props
  5. 刪除原本的 Clock function component

每當畫面更新時,就會呼叫一次 render()

在 class 加 Local State(本地端的 state)

三步驟:

  1. 加入一個 class constructor 建構子,分派(assign)初始的本地端 state this.state
    *class component 呼叫基本建構子(base constructor)時,永遠要傳 props
  2. render()this.props.date 替換成this.state.date
  3. 移除 Clock 標籤原本帶有的 JSX 屬性

在 class 加入生命週期(Lifecycle)的用法

在用到很多元件(components)的應用程式中,釋放那些被銷毀的元件的資源是很重要的。

React 的兩個生命週期

可在 component class 宣告兩個特別的函式,用來跑在當元件在 mount 或 uncount 的時候,如下:

這就是「生命週期用法」(lifecycle methods)。

  • mounting:在元件初次被渲染到 DOM 後(我們要在這建立一個計時器)
可在 class component 中自由增加需要的資料(例如:this.timerID
  • unmounting:元件產生的 DOM 被移除時(我們要清除計時器)

實作函式 tick():

要點重述:

  1. <Clock /> 被傳入到 ReactDOM.render() 時,React 呼叫 Clock 元件的建構子,初始化帶有一個物件的 this.state,顯示出目前時間。
  2. 接著 React 呼叫 Clock 元件的 render(),React 更新 DOM 符合 Clock 渲染的畫面。
  3. 當 Clock 的畫面嵌入 DOM,React 呼叫生命週期用法的 componentDidMount(),這個用法裡面 Clock 元件向瀏覽器要求設定一個一秒後呼叫 tick() 的計時器。
  4. 每當瀏覽器呼叫 tick(),Clock 元件透過帶有當下時間物件的 setState() 安排 UI 的更新。因為呼叫了 setState(),React 得以知道 state 被改變了,React 會再去呼叫 render() 看看現在應該要將什麼渲染在畫面上。而此時 render() 內的 this.state.date 將會不同,所以渲染的結果會包含更新後的時間,然後 React 根據此結果更新 DOM。
  5. 如果 Clock 元件被從 DOM 中移除,React 會呼叫生命週期用法 componentWillUnmount() 所以計時器會被停止。

正確地使用 State

  1. 勿直接修改 state,要用 setState()

*只有在建構子中可以指派 this.state

2. State 的更新可能是非同步的

React 為了效能,可能將數個呼叫 setState() 的動作批次處理成單一次更新。

由於 this.propsthis.state 的更新可能是非同步的,不該依賴他們的值去計算接下來的 state,例如:

可用第二種 setState() 型式,接收函式的方法解決:

這個函式的第一個參數是先前的 state、第二個參數是這個時間點更新的 props。

3. React 用合併的方式更新 state

當 setState() 被呼叫時,React 會合併裡面的物件到目前的 state。

this.setState({comments}) 保持 this.state.posts 的完整,但它完全取代了 this.state.comments

資料流向下

無論父元件或子元件,都無法知道某個元件有沒有 state,而且他們不需要在意元件是透過 function component 還是 class component 定義的。

這就是為何 state 常被稱為本地的(local)或封裝的(encapsulated)。

除了擁有和設置這個 state 的元件,任何其他組件都無法存取使用該 state。

一個元件可以透過將自己的 state 表示成 props(屬性),傳給他的子元件:

而子元件 FormatteDate 會透過 props 接收到資料,但不會知道這資料哪來的:

這通常被稱作為「上至下」或「單向」的資料流。

任何 state 都是被特定元件擁有,且任何從此 state 衍伸出的資料或 UI 只能影響到在此元件樹(component tree)以下的元件。

在有 state 的元件中能使用沒有 state 的元件,反之亦然。

--

--

No responses yet