開發與維運

React框架生命週期總結

生命週期(Life Cycle):是指一個對象的生老病死。此處的生命週期指的是在對應的框架中一個組件(對象)或程序從創建到銷燬的過程。

React生命週期圖

react-life-cycle.png

React生命週期詳解

React生命週期大體分為四個週期: 初始化、掛載、更新、卸載。

1.初始化期:

  • getDefautProps (es6: static defaultProps)
  • getInitialState (es6: constructor(props))

2.掛載期:

  • componentWillMount
  • render
  • componentDidMount

3.更新期

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

4.卸載

  • componentWillUnmount

    示例演示

初始化和掛載期代碼演示:

src/index.js

import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

src/App.js


class App extends Component {
  static defaultProps = {
    title: (() => {
      console.log(`defaultProps 初始期`)
      return 'app';
    })()
  }

  constructor(props) {
    super(props);
    this.state = {
      name: (() => {
        console.log(`this.state constructor時期`);
        return 'react'
      })()
    }
  }

  componentWillMount() {
    console.log(`componentWillMount 方法`)
  }

  componentDidMount() {
    console.log(`componentDidMount 方法`)
  }

  componentWillReceiveProps() {
    console.log(`componentWillReceiveProps 方法`)
  }

  shouldComponentUpdate() {
    console.log(`shouldComponentUpdate 方法`)
  }

  componentWillUpdate() {
    console.log(`componentWillUpdate 方法`)
  }

  componentDidUpdate() {
    console.log(`componentDidUpdate 方法`)
  }

  componentWillUnmount() {
    console.log(`componentWillUnmount 方法`)
  }

  render() {
    console.log(`render 方法`)
    return <div>{this.props.title} {this.state.name}</div>
  }
}

export default App;

運行結果:

App.js:6 defaultProps 初始期
App.js:15 this.state constructor時期
App.js:22 componentWillMount 方法
App.js:50 render 方法
App.js:26 componentDidMount 方法

更新期代碼演示:

更新器分兩種情況,一種是自身變化(state),另一種是父組件變化(props)。

自身state變化的情況:

src/App.js


class App extends Component {
  static defaultProps = {
    title: (() => {
      console.log(`defaultProps 初始期`)
      return 'app';
    })()
  }

  constructor(props) {
    super(props);
    this.state = {
      name: (() => {
        console.log(`this.state constructor時期`);
        return 'react'
      })()
    }
  }

  componentWillMount() {
    console.log(`componentWillMount 方法`)
  }

  componentDidMount() {
    console.log(`componentDidMount 方法`)
  }

  componentWillReceiveProps() {
    console.log(`componentWillReceiveProps 方法`)
  }

  shouldComponentUpdate() {
    console.log(`shouldComponentUpdate 方法`)
    return true;
  }

  componentWillUpdate() {
    console.log(`componentWillUpdate 方法`)
  }

  componentDidUpdate() {
    console.log(`componentDidUpdate 方法`)
  }

  componentWillUnmount() {
    console.log(`componentWillUnmount 方法`)
  }

  handleClick() {
    console.log(`點擊了【按鈕】`);
    this.setState({
      name: 'vue'
    })
  }

  render() {
    console.log(`render 方法`)
    return (
    <div>
      <button onClick={() => this.handleClick()}>按鈕</button>
      <br />
      <span>
        {this.props.title} {this.state.name}
      </span>
    </div>
    )
  }
}

export default App;

運行結果:

App.js:6 defaultProps 初始期
App.js:15 this.state constructor時期
App.js:22 componentWillMount 方法
App.js:58 render 方法
App.js:26 componentDidMount 方法
App.js:51 點擊了【按鈕】
App.js:34 shouldComponentUpdate 方法
App.js:39 componentWillUpdate 方法
App.js:58 render 方法
App.js:43 componentDidUpdate 方法

父組件變化(props)的情況:

src/App.js

import Child from './Child';

class App extends Component {
  static defaultProps = {
    title: (() => {
      console.log(`defaultProps 初始期`)
      return 'app';
    })()
  }

  constructor(props) {
    super(props);
    this.state = {
      name: (() => {
        console.log(`this.state constructor時期`);
        return 'react'
      })()
    }
  }

  componentWillMount() {
    console.log(`componentWillMount 方法`)
  }

  componentDidMount() {
    console.log(`componentDidMount 方法`)
  }

  componentWillReceiveProps() {
    console.log(`componentWillReceiveProps 方法`)
  }

  shouldComponentUpdate() {
    console.log(`shouldComponentUpdate 方法`)
    return true;
  }

  componentWillUpdate() {
    console.log(`componentWillUpdate 方法`)
  }

  componentDidUpdate() {
    console.log(`componentDidUpdate 方法`)
  }

  componentWillUnmount() {
    console.log(`componentWillUnmount 方法`)
  }

  handleClick() {
    console.log(`點擊了【按鈕】`);
    this.setState({
      name: 'vue'
    })
  }

  render() {
    console.log(`render 方法`)
    return (
    <div>
      <button onClick={() => this.handleClick()}>按鈕</button>
      <br />
      <Child title={this.state.name}/>
    </div>
    )
  }
}

export default App;

src/Child.jsx


class Child extends Component {
  
  constructor(props) {
    super(props);
    console.log(`constructor 方法`)
  }

  componentWillMount() {
    console.log(`componentWillMount 方法`)
  }

  componentDidMount() {
    console.log(`componentDidMount 方法`)
  }

  componentWillReceiveProps() {
    console.log(`componentWillReceiveProps 方法`)
  }

  shouldComponentUpdate() {
    console.log(`shouldComponentUpdate 方法`)
    return true;
  }

  componentWillUpdate() {
    console.log(`componentWillUpdate 方法`)
  }

  componentDidUpdate() {
    console.log(`componentDidUpdate 方法`)
  }

  componentWillUnmount() {
    console.log(`componentWillUnmount 方法`)
  }

  render() {
    console.log(`render 方法`)
    return (
    <div>
      {this.props.title}
    </div>
    )
  }
}

export default Child;

運行結果:

App.js:7 defaultProps 初始期
App.js:16 this.state constructor時期
App.js:23 componentWillMount 方法
App.js:59 render 方法
Child.jsx:7 constructor 方法
Child.jsx:11 componentWillMount 方法
Child.jsx:40 render 方法
Child.jsx:15 componentDidMount 方法
App.js:27 componentDidMount 方法
App.js:52 點擊了【按鈕】
App.js:35 shouldComponentUpdate 方法
App.js:40 componentWillUpdate 方法
App.js:59 render 方法
Child.jsx:19 componentWillReceiveProps 方法
Child.jsx:23 shouldComponentUpdate 方法
Child.jsx:28 componentWillUpdate 方法
Child.jsx:40 render 方法
Child.jsx:32 componentDidUpdate 方法
App.js:44 componentDidUpdate 方法

卸載期演示:

src/App.js

import Child from './Child';

class App extends Component {
  static defaultProps = {
    title: (() => {
      console.log(`defaultProps 初始期`)
      return 'app';
    })()
  }

  constructor(props) {
    super(props);
    this.state = {
      name: (() => {
        console.log(`this.state constructor時期`);
        return 'react'
      })()
    }
  }

  componentWillMount() {
    console.log(`componentWillMount 方法`)
  }

  componentDidMount() {
    console.log(`componentDidMount 方法`)
  }

  componentWillReceiveProps() {
    console.log(`componentWillReceiveProps 方法`)
  }

  shouldComponentUpdate() {
    console.log(`shouldComponentUpdate 方法`)
    return true;
  }

  componentWillUpdate() {
    console.log(`componentWillUpdate 方法`)
  }

  componentDidUpdate() {
    console.log(`componentDidUpdate 方法`)
  }

  componentWillUnmount() {
    console.log(`componentWillUnmount 方法`)
  }

  handleClick() {
    console.log(`點擊了【按鈕】`);
    this.setState({
      name: 'vue'
    })
  }

  render() {
    console.log(`render 方法`)
    return (
    <div>
      <button onClick={() => this.handleClick()}>按鈕</button>
      <br />
      { this.state.name === 'react' ? <Child title={this.state.name}/> : null }
    </div>
    )
  }
}

export default App;

運行結果:

App.js:7 defaultProps 初始期
App.js:16 this.state constructor時期
App.js:23 componentWillMount 方法
App.js:59 render 方法
Child.jsx:7 constructor 方法
Child.jsx:14 componentWillMount 方法
Child.jsx:46 render 方法
Child.jsx:18 componentDidMount 方法
App.js:27 componentDidMount 方法
App.js:52 點擊了【按鈕】
App.js:35 shouldComponentUpdate 方法
App.js:40 componentWillUpdate 方法
App.js:59 render 方法
Child.jsx:42 componentWillUnmount 方法
App.js:44 componentDidUpdate 方法

各個回調方法的特性

constructor:

constructor函數是在對應組件初始化時調用的構造方法,構造方法就是該組件的出生方法,對應的對象只能出生一次,所以對應的實例組件一生只能調用一次,除非銷燬重新生成。該方法的執行時間點是靜態資源初始化執行後(static修飾的屬性),componentWillMount方法執行前執行。constructor方法帶有一個參數是props,參數props是父級中調用該組件時設置的屬性集對象。該方法中第一行必須調用 super(props); 因為實現的組件都是繼承自React.Compent對象,調用這個方法才能實現父組件props變化時自身渲染結果隨之改變。

特性:

• 參數props父級傳遞下來的props對象
• constructor中必須寫super(props)
• 組件初始化的時候調用,整個生命週期中只調用一次
• 在類中的靜態資源加載完後執行(static defaultProps就是靜態資源)

用途:

該方法的主要用途是用來初始化組件中的屬性和定義屬性的。所以我們一般都在這個方法中定義state中的屬性,或定義一下實例變量。

componentWillMount

componentWillMount() 這個生命週期方法是React的第一個生命週期方法,該方法在組件對象的基礎屬性及方法都初始化完成後調用,調用這個方法就是說React開始準備接管這個對象了。

特性:

• 在組件掛載到DOM前調用,且只會被調用一次
• 調用this.setState不會引起組件重新渲染(此時還沒有掛載到DOM上)

用途:

該方法中主要是初始化一下數據或在組件初始化的時候去請求數據。

componentDidMount

componentDidMount() 這個生命週期方法應該是用的最多的,一般用在進入頁面後,數據初始化。componentDidMount與componentWillMount的區別是:componentWillMount是在render方法前調用的,componentDidMount是在render方法後調用的,render方法後對應的該組件就掛載到DOM上了,就可以完全被react接管了,此時可以調用this.setState方法了。

特性:

• 組件掛載到DOM後調用,且只會被調用一次
• 掛載到DOM後調用this.setState就會引起組件重新渲染

用途:

該方法中與componentWillMount用法差不多,但是這個方法中可以調用this.setState,可以重新渲染界面。

componentWillReceiveProps

componentWillReceiveProps(nextProps) 這個生命週期的方法是在組件掛載到DOM後屬性變化後調用的。組件中的屬性是由父組件中傳遞過來的值,在這個方法中可以判斷父組件中傳過來的值和該組件內值是否相等來判斷是否指定屬性改變了,來處理特定屬性的行為。

特性:

• 參數是nextProps改變後的props對象
• 調用 this.setState不會引起第二次渲染,所以可以在此函數中根據props的變化設置state的值
• 當前組件中的this.props還是原來的值,還沒有變化

用途:

該方法主要是來監控屬性props的變化的,對特殊屬性props的變化做出特別處理。可以過濾出對應屬性變化來重新渲染組件,防止組件屬性改變每次都渲染組件。

shouldComponentUpdate

shouldComponentUpdate(nextProps, nextState) 這個生命週期的方法是在props和state屬性變化後都會調用的方法,用來判斷是否需要重新渲染。此方法中的返回值用來決定是否重新渲染,返回true表示需要重新渲染,返回false反之。此方法返回true後會調用componentWillUpdate方法。

特性:

• 參數nextProps、nextState 分別表示變化後的props和state
• 當前組件中的this.props和this.state還是原來的值,還沒有變化
• 可比較this.props、this.state和nextProps、nextState 中的值是否有變化
• 此函數return一個布爾值,表示是否需要重新渲染DOM

用途:

我們可以通過shouldComponentUpdate生命週期函數來來判斷當前組件所在的props、state和context發生改變時,當前組件還是否需要進行更新操作(可以認為為當前組件自定義一個diff算法),以達到性能的最大優化。

componentWillUpdate

componentWillUpdate(nextProps, nextState) 這個生命週期的方法是在shouldComponentUpdate方法後調用,此方法調用後就會去調用render方法重新渲染界面。此方法中的參數是props變化後的值(父組件傳遞進來的值),該組件中的props還是原來的值還沒有改變。

特性:

• 參數nextProps、 nextState 分別表示變化後的props和state
• 當前組件中的this.props和this.state還是原來的值,還沒有變化
• 此方法在調用render方法前執行

用途:

DOM重新渲染前調用,用來查看界面最後渲染時值的前後變化。

componentDidUpdate

componentDidUpdate(prevProps, prevState) 這個生命週期的方法是在componentWillUpdate方法後調用過render後再調用。此方法調用後表示一個渲染過程完成。

特性:

• 參數prevProps, prevState 分別表示變化前的props和state
• 當前組件中的this.props和this.state的值已經變化
• 此方法掉用render方法後執行

用途:

DOM重新渲染後調用,可以用了查看渲染後屬性值的前後變化。

componentWillUnmount

componentWillUnmount() 這個生命週期的方法是在組件銷燬前調用。

特性:

• 此方法在組件被卸載前調用,可以在這裡執行一些清理工作

用途:

組件銷燬前做一些清理工作。如:clearTimeout, clearInterval

render

render() 方法用來重新渲染界面。

特性:

• 在componentWillMount後,componentDidMount前會被調用一次
• 在componentWillUpdate後,componentDidUpdate前會被調用
• 不能執行this.setState(會死循環)

Leave a Reply

Your email address will not be published. Required fields are marked *