React

React Component 的生命週期

王新漢 Kevin Wang 2020/12/13 01:02:18
944
  • 寫 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 儘量只專注於頁面設計而非資料處理
王新漢 Kevin Wang