React Component 的生命週期
- 寫 React 前最重要的是要認識整個 Component 的生命週期
-
import PropTypes from 'prop-types'; import * as React from "react"; export default class MyComponent extends React.Component { constructor(props) { super(props); // Component render 前觸發,整個 Component 的生命週期中只會觸發一次 // 如果需要在 constructor 中使用 this.props 則執行 super(props),否則執行 super() this.state = {}; // 設定整個 Component 初始狀態,只能在 constructor 中使用,之後要更新 state 一律使用 this.setState({}) } componentDidMount() { // Component render 完成後觸發,整個 Component 的生命週期中只會觸發一次 } componentWillReceiveProps(nextProps) { // Component 收到 properties 時觸發,會在 render 前就執行 } componentDidUpdate() { // Component render 完成後觸發,首次安裝 Component 時不會觸發,之後的重新 render 才會觸發 } shouldComponentUpdate(nextProps, nextState) { // Component 是否需要被重新 render,須 return true or false } render() { // 在這邊 return 要 render 的 html tag 或其他 Component return ( <span /> ) } } // 定義 Component 要傳入的參數,應提供註解說明每個參數 MyComponent.propTypes = { page: PropTypes.object, onPageClick: PropTypes.func.isRequired, maxButtons: PropTypes.number }; // 定義 Component 的 default properties,props 才是在此定義,state 在 constructor 中用 this.state = {} 定義 MyComponent.defaultProps = { maxButtons: 5 };
-
假設現在有一個 Component 首次被執行後會在 componentDidMount 去 Server 端要資料並更新當前這個 Component, 那整個生命週期會是
constructor() -> render() -> componentDidMount() -> componentWillReceiveProps() -> shouldComponentUpdate() -> render() -> componentDidUpdate()
-
如果該 Component 一直存在頁面上,那第二次以後取得資料時他的生命週期會是
componentWillReceiveProps() -> shouldComponentUpdate() -> render() -> componentDidUpdate()
-
如果在 shouldComponentUpdate() 回傳了 false,則
render() -> componentDidUpdate()
這段將不會被執行 -
this.setState({})
用於更新 Component 的狀態資料,一但執行了 Component 就會被重新 render -
如果要在 componentDidUpdate() 中執行 this.setState({}) 則務必增加 shouldComponentUpdate() 的判斷, 否則將造成無窮迴圈
-
this.setState 是非同步的
-
handleChange = (e) => { this.setState({value: e.target.value}); console.log(this.state.value); }
-
以上程式碼並不保證可以取到更新後的 value,這是因為 React 的 setState 本身是個非常複雜的計算過程, 會經過 React 自身的 diff 演算法,最終得出需要重新 render 的元件,並且為了避免使用者在極短時間內下達 了多次 setState 而造成過度渲染的問題,所以 setState 被設計為延時執行,目的是為了將短時間內的多個 setState 進行合併
-
如果一定要在 state 確認更新後取到值,可以在 setState 傳入第 2 個 callback function 參數
-
this.setState({value: e.target.value}, () => { console.log(this.state.value) })
-
Control value & Uncontrol value
- Control value 指的是 input 的 value 被綁定於一個 state 物件,也就是這個 input 是 stateful,任何的 state 更動都將連帶變動 input 的 value,此時 input 顯示的值只有透過 setState 時才會變動,如果沒有下 setState 則 不管在頁面輸入任何值都將不會更動 input,此 input 受控於 Component 的 state,而不是自身的 DOM
-
<input type="text" className="form-control" name="account" placeholder="Account" value={this.state.account} onChange={this.handleChange}/>
- Uncontrol value 指的是 input 的 value 不綁定於任何物件,也就是這個 input 是 stateless,任何的 state 更動都不會變動 input 的 value,此 input 受控於自身的 DOM
-
<input type="text" className="form-control" name="account" placeholder="Account" defaultValue={this.account} onChange={this.handleChange}/>
- Redux 改良自 Facebook 提出的 Flux 架構,與 Flux 相同採用單向資料流,並將複雜的資料邏輯處理交給 Reducer,讓 Component 儘量只專注於頁面設計而非資料處理