14曙聂、React系列之--組件的生命周期

版權(quán)聲明:本文為博主原創(chuàng)文章偿枕,未經(jīng)博主允許不得轉(zhuǎn)載颅湘。

PS:轉(zhuǎn)載請注明出處
作者:TigerChain
地址:http://www.reibang.com/p/e3d1ecfb6312
本文出自TigerChain簡書
git 地址:https://github.com/tigerchain/react-lesson

教程簡介

  • 1话侧、閱讀對象

本篇教程適合初學(xué)者,老鳥直接略過闯参,如果有誤,歡迎指出悲立,謝謝鹿寨。

正文

1原献、什么是生命周期

生命周期指的是一個對象的生老病死馏慨。當(dāng)然生命周期又為廣義和狹義的。具體分為以下幾類姑隅。

  • 1写隶、動物的生命周期:從初生到死亡。
  • 2讲仰、產(chǎn)品的生命周期:從開始到淘汰慕趴。(一般指提市場壽命)
  • 3、語言或平臺中某個組件的生命周期:比如 activity 的生命周期鄙陡,指的就是 activity 的創(chuàng)建到銷毀的過程冕房。
  • 4、其它生命周周期

2趁矾、React 的生命周期

先看 React 的生命周期圖耙册,雖然你可能不理解,通過后面的學(xué)習(xí)再回頭來看這幅圖毫捣,就會恍然大悟详拙。

ReactLifeCycler.jpeg

一、這里說的 React 的生命周期指的就是 React 組件的生命周期培漏。React Component 通過定義幾個函數(shù)來控制組件在生命周期每個階段的功能溪厘。

總的來說 React 組件的生命周期有三種狀態(tài)

1、mounting: 插入真實 DOM </br>
2牌柄、updating: 正在被重新渲染 props 或 state 改變 </br>
3畸悬、unmounting: 卸載 移除真實 DOM

在 React 中為每個狀態(tài)又分別提供了兩種處理函數(shù),就是 will 和 did , will 是進入狀態(tài)之前調(diào)用的, did 是進入狀態(tài)之后調(diào)用的.

總的來說蹋宦,三種狀態(tài)對應(yīng)不同的函數(shù)

  • mounting 對應(yīng)的函數(shù)
constructor()
componentWillMount()
render()
componentDidMount()
  • updating 對應(yīng)的函數(shù)
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
  • unmounting 對應(yīng)的函數(shù)
componentWillUnmount()

PS:一個組件中 redner() 方法是必須的披粟。

二、和組件生命周期相關(guān)的函數(shù)有

上面籠統(tǒng)的說了一下和組件生命周期相關(guān)的方法冷冗,我們下面逐一來說明守屉。

  • 1、構(gòu)造函數(shù)
constructor(props, context)

構(gòu)造函數(shù),在組件創(chuàng)建的時候調(diào)用一次蒿辙。

  • 2拇泛、componentWillMount()
void componentWillMount()

在組件掛載之前( render()之前 )調(diào)用∷脊啵可以用于加載 Loading 條了等操作俺叭。

  • 3、render
render() ;

render 方法顧名思義泰偿,就是渲染的意思熄守,它有一個返回值,就是返回一個 React 元素(自定義組件或是呈現(xiàn) DOM 組件的元素)耗跛,當(dāng)然如果你什么也不想返回就可以 return null 或 return false (組件就不顯示了)裕照,render() 里面應(yīng)該是純凈的 (不能在里面修改組件的狀態(tài),也不能在里面請求服務(wù)器等耗時操作[ componentDidMount 方法中進行耗時操作])调塌,只是用來渲染組件晋南。

  • 4、componentDidMount()
void componentDidMount()

在組件掛載之后調(diào)用烟阐“峥。可以用于耗時操作(請求服務(wù)器或定時器等)。

  • 5蜒茄、componentWillReceiveProps()
void componentWillReceiveProps(nextProps)

這里的 props 是父組件傳遞給子組件的唉擂。父組件發(fā)生 render 的時候就會調(diào)用子組件的 componentWillReceiveProps (不管 props 有沒有更新,也不管父子組件之間有無數(shù)據(jù)交換),在這個回調(diào)函數(shù)里面檀葛,你可以根據(jù)屬性的變化玩祟,通過調(diào)用this.setState()來更新你的組件狀態(tài),舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的屿聋,并不會觸發(fā)額外的render調(diào)用空扎。

  • 6、shouldComponentUpdate()
bool shouldComponentUpdate(nextProps, nextState)

這個方法在組件掛載之后润讥,當(dāng)你調(diào)用 setState() 方法的時候都會調(diào)用此方法用來判斷是否要重新渲染組件转锈,如果返回 true 則需要重新渲染,如果是 false 則不會楚殿。我們可以在這個方法中處理只是數(shù)據(jù)改變撮慨,界面不改變的情況,用來優(yōu)化渲染效率。

  • 7砌溺、componentWillUpdate()
void componentWillUpdate(nextProps, nextState)

顧名思義影涉,就是組件更新前被調(diào)用的方法,具體是當(dāng) props 和 state 發(fā)生改變的時候就會執(zhí)行此方法并且在 redner() 方法之前進行规伐。這個方法也在 shouldComponentUpdate() 方法返回 true 的時候就會調(diào)用蟹倾,返回 false 不會調(diào)用, 使用此方法為更新前做一些準備。初始化渲染的時候不會調(diào)用這個方法猖闪。

PS:注意一點鲜棠,在這個方法中不能會用 this.setState() 方法來修改狀態(tài)。當(dāng)這個函數(shù)調(diào)用之后培慌,就會把 nextProps 和 nextState 分別設(shè)置到 this.props 和 this.nextState 方法中岔留,接著就會調(diào)用 render() 方法來渲染了。

  • 8检柬、componentDidUpdate()
void componentDidUpdate()

組件渲染后就會調(diào)用 componentDidUpdate() 方法,但是首次 render() 的時候是不會調(diào)用的竖配,首次 render() 的時候調(diào)用的是 componentDidMount() 方法何址。

componentWillMount()、componentDidMount 和 componentWillUpdate()进胯、componentDidUpdate 是一一對應(yīng)的用爪,前者是在掛載的時候會被調(diào)用,但是后者是每次更新渲染之后都會調(diào)用胁镐。

  • 9偎血、componentWillUnmount()
void componentWillUnmount()

組件被卸載的時候調(diào)用,一般情況下在 componentWillUnmount() 說法中清除注冊的事件盯漂,比如取消定時器颇玷,網(wǎng)絡(luò)請求等。

3就缆、React 中的更新方式

總的來說帖渠,在 React 中,想要 redner 有以下四種方式竭宰。

假使 shouldComponentUpdate 都是返回 true 的情況下

  • 1空郊、首次初化 render
  • 2、調(diào)用 this.setState() 方法 (我們知道它是異步的切揭,不是每調(diào)用一次 setState 都會觸發(fā)一次 render ,React 有時可能會合并操作狞甚,再一次進行 render)
  • 3、props 發(fā)生改變廓旬,但是一般不建議直接調(diào)用 this.setProps()
  • 4哼审、手動調(diào)用 this.forceUpdate(不推薦這樣使用)

到目前為止,我們大體對 React 組件的生命周期有一個了解了,下面我們通過 Demo 來直觀的感覺一下棺蛛。

4怔蚌、實例演示組件的生命周期

經(jīng)過上面的學(xué)習(xí),我們大體對 React 組件的生命周期有了一定的認識旁赊,下面我們寫一個 Demo 來驗證一下桦踊。

我們可以使用前面學(xué)過的知識使用 yarn + webpack + ES6 來創(chuàng)建項目,如果不懂這些知識终畅,可以看看前面相關(guān)的章節(jié)籍胯。以下 Demo 是在 mac 環(huán)境下開發(fā)的。

1离福、打開命令行杖狼,新建 lifecycle 目錄

mkdir lifecycle

2、進入到 lifecycle 文件夾下妖爷,并新建 public 和 app 目錄蝶涩。

cd lifecycle
mkdir public
mkdir app

3、分別在 app 中 和 public 中新建 index.html 和 main.js

# index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>React-LifeCycle</title>
</head>
<body>

<div id="container"></div>
<script src="bundle.js"></script>
</body>
</html>

# main.js

import React from 'react' ;
import ReactDOM from 'react-dom' ;

import LifeCycle from './LifeCycle.js' ;

/**
 * 定義一個父組件
 */
class Main extends React.Component{

  constructor(props){
    super(props) ;
    this.state = {
      name:'junjun'
    }
  }

   render(){
     return(
       <LifeCycle
         umout={this.unmoutComponent}
         name={this.state.name}
         testComponentWillReceiveProps={this.changeState.bind(this)}
       />
     ) ;
   }

   /**
    * 卸載組件
    */
   unmoutComponent(){
     // 這里卸載父組件也會導(dǎo)致卸載子組件
     ReactDOM.unmountComponentAtNode(document.getElementById("container"));
   }

/**
 * 通過修改 state 來修改 props 用來測試 componentWillReceiveProps 方法
 */
   changeState(){
     this.setState({
       name:'TigerChain11111'
     })
   }

}


ReactDOM.render(
  <Main />,
  document.getElementById('container')
) ;

在這里我一口氣寫完了絮识,注釋非常詳細绿聘,如果你學(xué)習(xí)過前面章節(jié)的知識,那么這個很容易看懂次舌。

4熄攘、在 app 中再新建 LifeCycle.js

# LifeCycle.js

import React, { Component, PropTypes } from 'react';

/**
 * 定義一個生命周期的組件
 */

export default class LifeCycle extends Component {

  constructor(props) {
    super(props);

    console.log("~~ Initial render ~~");
    console.log("~~ constructor ~~");

    alert("~~ Initial render ~~") ;
    alert("~~ constructor ~~") ;
    this.state = {
      name:'TigerChain'
    }
  }
  /**
   * 在掛載之前調(diào)用
   */
  componentWillMount(){
    console.log("~~ componentWillMout ~~");

    alert("~~ componentWillMout ~~") ;
  }

  render() {
    console.log("~~ render ~~");
    alert("~~ render ~~") ;
    return (
      <div>
        LifeCycle Demo <p/>
        <button onClick={this._changeProps.bind(this)}>changeProps</button><p/>

        <button onClick={this._setState.bind(this)}>setState</button><p/>

        <button onClick={this._forceWithUpdate.bind(this)}>forceWithUpdate</button><p/>

        <button onClick={this._unmout.bind(this)}>unmout</button><p/>

        <button onClick={this.koukou.bind(this)}>parentChangeProps</button> <p/>

    </div>);
  }
  /**
   * 測試 ComponentWillReceiveProps 方法
   */
  koukou(){
    this.props.testComponentWillReceiveProps() ;
  }

  /**
   * 在掛載之后調(diào)用
   */
  componentDidMount(){
    console.log("~~ componentDidMout ~~");
    alert("~~ componentDidMout ~~") ;
  }

  /**
   * 組件掛載之后 當(dāng)調(diào)用 setState() 的時候  如果此方法返回 true ,則會重新渲染彼念,否則不會
   */
  shouldComponentUpdate(nextProps, nextState){
      console.log("~~ shouldComponentUpdate ~~");
      console.log("shouldComponentUpdate nextState",nextState);
      alert("~~ shouldComponentUpdate ~~"+nextState) ;
      return true ;
  }

  /**
   * props 改變的時候調(diào)用
   */
  componentWillReceiveProps(nextProps){
    console.log("~~ componentWillReceiveProps ~~");
    alert("~~ componentWillReceiveProps ~~") ;
  }
  /**
   * shouldComponentUpdate 返回 true 的時候 將要更新
   */
  componentWillUpdate(nextProps, nextState){
    console.log("componentWillUpdate nextState",nextState);
    console.log(this.state.name);
    console.log("~~ componentWillUpdate ~~");

    alert("~~ componentWillUpdate ~~") ;
  }

  /**
   * 組件已經(jīng)更新
   */
  componentDidUpdate(){
    console.log("~~ componentDidUpdate ~~");
    alert("~~ componentDidUpdate ~~") ;
  }

  /**
   * 組件將要卸載
   */
  componentWillUnmount(){
    console.log("~~ componentWillUnmount ~~");
    alert("~~ componentWillUnmount ~~") ;
  }

  /**
   * 組件卸載的方法
   */
  _unmout(){
    this.props.umout();
  }

  _forceWithUpdate(){
    this.forceUpdate();
  }
  /**
   * 修改屬性
   */
  _changeProps(){
    this.setState({
      name:'TigerChain1'
    })
  }

  /**
   * 修改 state 方法
   */
  _setState(){
    var that = this ;
    if((that.state.name === "TigerChain1") || (that.state.name="TigerChain")){
      that.setState({
        name:'TigerChainJun'
      });
    }
  }
}

我們在這里把組件生命周期的 demo 就寫完了挪圾,具體可以看注釋。

5逐沙、添加 react react-dom babel 等插件依賴

yarn add react react-dom babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0 webpack webpack-dev-server --dev

這里也不多說哲思,如果不懂的話,可以查看 webpack 這一節(jié)酱吝。

6也殖、在項目根目錄新建 .babelrc 文件并輸入以下內(nèi)容

{
  "presets": ["react", "es2015","stage-0"]
}

7、在根目錄新建 webpack.config.js 并配置

# webpack.config.js

module.exports = {
  entry: __dirname+"/app/main.js",
  output:{
    path:__dirname + "/public",
    filename:"bundle.js"
  },
  module: {
    loaders: [
      //babel配置
    {
      test:/\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }
  ]
  },
  devServer:{
    contentBase: "./public",//本地服務(wù)器所加載的頁面所在的目錄
    historyApiFallback: true,//不跳轉(zhuǎn)
    inline: true//實時刷新
  }
}

8务热、配置腳本 package.json

{
  "name": "11-lifecycle",
  "version": "1.0.0",
  "main": "index.js",
  "author": "TigerChain",
  "license": "ISC",
  "scripts":{
    "start":"webpack-dev-server --progress --port 8888"
  },
  "devDependencies": {
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.1",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "babel-preset-stage-0": "^6.22.0",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "webpack": "^2.3.2",
    "webpack-dev-server": "^2.4.2"
  }
}

9忆嗜、運行查看 yarn start 并在瀏覽器中輸入 localhost:8888 如果不出什么問題,那么我們就可以看到如下界面

lifecycle.gif

圖中就完整的展示了 React 組件的生命周期崎岂。我們回過頭再去看前面的生命周期圖捆毫,就能很好的理解了。請大家務(wù)必照著 demo 敲一遍代碼冲甘,以便加深理解绩卤。(老鳥直接略過)

到此為止途样,我們的 React 組件的生命周期就講完了。

如果喜歡濒憋,就點個喜歡吧何暇。

Demo 地址

https://github.com/tigerchain/react-lesson/tree/master/lesson02/11-lifecycle

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凛驮,隨后出現(xiàn)的幾起案子裆站,更是在濱河造成了極大的恐慌,老刑警劉巖黔夭,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宏胯,死亡現(xiàn)場離奇詭異,居然都是意外死亡本姥,警方通過查閱死者的電腦和手機肩袍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來婚惫,“玉大人氛赐,你說我怎么就攤上這事∠认希” “怎么了鹰祸?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長密浑。 經(jīng)常有香客問我,道長粗井,這世上最難降的妖魔是什么尔破? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮浇衬,結(jié)果婚禮上懒构,老公的妹妹穿的比我還像新娘。我一直安慰自己耘擂,他們只是感情好胆剧,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著醉冤,像睡著了一般秩霍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚁阳,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天铃绒,我揣著相機與錄音,去河邊找鬼螺捐。 笑死颠悬,一個胖子當(dāng)著我的面吹牛矮燎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赔癌,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诞外,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了灾票?” 一聲冷哼從身側(cè)響起峡谊,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铝条,沒想到半個月后靖苇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡班缰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年贤壁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埠忘。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡脾拆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莹妒,到底是詐尸還是另有隱情名船,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布旨怠,位于F島的核電站渠驼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鉴腻。R本人自食惡果不足惜迷扇,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爽哎。 院中可真熱鬧蜓席,春花似錦、人聲如沸课锌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渺贤。三九已至雏胃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間志鞍,已是汗流浹背丑掺。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留述雾,地道東北人街州。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓兼丰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唆缴。 傳聞我的和親對象是個殘疾皇子鳍征,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容