[官網學 React] Docs:State 和生命週期
網址(英文):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()
做渲染,如以下例子:
上面例子透過每一秒呼叫一次 setInterval()
callback,讓 ReactDOM.render()
能一秒重新渲染一次。
這篇官網會教我們如何使這個時鐘元件能被重複使用和封裝,它將會設定自己的 timer 並每秒更新一次。
封裝 Clock Component
但目前還是得依賴 setInterval() 才能做到畫面每秒渲染一次。
我們的目標是 Clock 組件建立一個計時器後,能每秒自動更新 UI,最後能寫成以下這樣:
要能做到這樣,需要在 Clock 元件新增 state。
state 類似 props,差異是 state 是 component 能完全掌控的,且是非公開的(private)。
將 Function 轉換成 class
將 Clock 物件從 function component 轉成 class component 五步驟:
- 建立一個名稱也是 Clock 的 ES6 class,繼承
React.Component
- 新增一個空函式
render()
- 將原本 function component 的全部內容搬進
render()
- 在
render()
的 body 裡用this.props
取代props
- 刪除原本的 Clock function component
每當畫面更新時,就會呼叫一次 render()
。
在 class 加 Local State(本地端的 state)
三步驟:
- 加入一個 class constructor 建構子,分派(assign)初始的本地端 state
this.state
*class component 呼叫基本建構子(base constructor)時,永遠要傳 props - 在
render()
將this.props.date
替換成this.state.date
- 移除 Clock 標籤原本帶有的 JSX 屬性
在 class 加入生命週期(Lifecycle)的用法
在用到很多元件(components)的應用程式中,釋放那些被銷毀的元件的資源是很重要的。
React 的兩個生命週期
可在 component class 宣告兩個特別的函式,用來跑在當元件在 mount 或 uncount 的時候,如下:
這就是「生命週期用法」(lifecycle methods)。
- mounting:在元件初次被渲染到 DOM 後(我們要在這建立一個計時器)
this.timerID
)- unmounting:元件產生的 DOM 被移除時(我們要清除計時器)
實作函式 tick():
要點重述:
- 當
<Clock />
被傳入到ReactDOM.render()
時,React 呼叫 Clock 元件的建構子,初始化帶有一個物件的this.state
,顯示出目前時間。 - 接著 React 呼叫 Clock 元件的 render(),React 更新 DOM 符合 Clock 渲染的畫面。
- 當 Clock 的畫面嵌入 DOM,React 呼叫生命週期用法的
componentDidMount()
,這個用法裡面 Clock 元件向瀏覽器要求設定一個一秒後呼叫 tick() 的計時器。 - 每當瀏覽器呼叫 tick(),Clock 元件透過帶有當下時間物件的 setState() 安排 UI 的更新。因為呼叫了 setState(),React 得以知道 state 被改變了,React 會再去呼叫 render() 看看現在應該要將什麼渲染在畫面上。而此時 render() 內的
this.state.date
將會不同,所以渲染的結果會包含更新後的時間,然後 React 根據此結果更新 DOM。 - 如果 Clock 元件被從 DOM 中移除,React 會呼叫生命週期用法
componentWillUnmount()
所以計時器會被停止。
正確地使用 State
- 勿直接修改 state,要用 setState()
*只有在建構子中可以指派 this.state
2. State 的更新可能是非同步的
React 為了效能,可能將數個呼叫 setState() 的動作批次處理成單一次更新。
由於 this.props
和 this.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 的元件,反之亦然。