ReactWeb前端之路让前端飞

14、React系列之--组件的生命周期

2017-04-11  本文已影响933人  TigerChain

版权声明:本文为博主原创文章,未经博主允许不得转载。

PS:转载请注明出处
作者:TigerChain
地址:http://www.jianshu.com/p/e3d1ecfb6312
本文出自TigerChain简书
git 地址:https://github.com/githubchen001/react-lesson

教程简介

本篇教程适合初学者,老鸟直接略过,如果有误,欢迎指出,谢谢。

正文

1、什么是生命周期

生命周期指的是一个对象的生老病死。当然生命周期又为广义和狭义的。具体分为以下几类。

2、React 的生命周期

先看 React 的生命周期图,虽然你可能不理解,通过后面的学习再回头来看这幅图,就会恍然大悟。

ReactLifeCycler.jpeg

一、这里说的 React 的生命周期指的就是 React 组件的生命周期。React Component 通过定义几个函数来控制组件在生命周期每个阶段的功能。

总的来说 React 组件的生命周期有三种状态

1、mounting: 插入真实 DOM </br>
2、updating: 正在被重新渲染 props 或 state 改变 </br>
3、unmounting: 卸载 移除真实 DOM

在 React 中为每个状态又分别提供了两种处理函数,就是 will 和 did , will 是进入状态之前调用的, did 是进入状态之后调用的.

总的来说,三种状态对应不同的函数

constructor()
componentWillMount()
render()
componentDidMount()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
componentWillUnmount()

PS:一个组件中 redner() 方法是必须的。

二、和组件生命周期相关的函数有

上面笼统的说了一下和组件生命周期相关的方法,我们下面逐一来说明。

constructor(props, context)

构造函数,在组件创建的时候调用一次。

void componentWillMount()

在组件挂载之前( render()之前 )调用。可以用于加载 Loading 条了等操作。

render() ;

render 方法顾名思义,就是渲染的意思,它有一个返回值,就是返回一个 React 元素(自定义组件或是呈现 DOM 组件的元素),当然如果你什么也不想返回就可以 return null 或 return false (组件就不显示了),render() 里面应该是纯净的 (不能在里面修改组件的状态,也不能在里面请求服务器等耗时操作[ componentDidMount 方法中进行耗时操作]),只是用来渲染组件。

void componentDidMount()

在组件挂载之后调用。可以用于耗时操作(请求服务器或定时器等)。

void componentWillReceiveProps(nextProps)

这里的 props 是父组件传递给子组件的。父组件发生 render 的时候就会调用子组件的 componentWillReceiveProps (不管 props 有没有更新,也不管父子组件之间有无数据交换),在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。

bool shouldComponentUpdate(nextProps, nextState)

这个方法在组件挂载之后,当你调用 setState() 方法的时候都会调用此方法用来判断是否要重新渲染组件,如果返回 true 则需要重新渲染,如果是 false 则不会。我们可以在这个方法中处理只是数据改变,界面不改变的情况,用来优化渲染效率。

void componentWillUpdate(nextProps, nextState)

顾名思义,就是组件更新前被调用的方法,具体是当 props 和 state 发生改变的时候就会执行此方法并且在 redner() 方法之前进行。这个方法也在 shouldComponentUpdate() 方法返回 true 的时候就会调用,返回 false 不会调用, 使用此方法为更新前做一些准备。初始化渲染的时候不会调用这个方法。

PS:注意一点,在这个方法中不能会用 this.setState() 方法来修改状态。当这个函数调用之后,就会把 nextProps 和 nextState 分别设置到 this.props 和 this.nextState 方法中,接着就会调用 render() 方法来渲染了。

void componentDidUpdate()

组件渲染后就会调用 componentDidUpdate() 方法,但是首次 render() 的时候是不会调用的,首次 render() 的时候调用的是 componentDidMount() 方法。

componentWillMount()、componentDidMount 和 componentWillUpdate()、componentDidUpdate 是一一对应的,前者是在挂载的时候会被调用,但是后者是每次更新渲染之后都会调用。

void componentWillUnmount()

组件被卸载的时候调用,一般情况下在 componentWillUnmount() 说法中清除注册的事件,比如取消定时器,网络请求等。

3、React 中的更新方式

总的来说,在 React 中,想要 redner 有以下四种方式。

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

到目前为止,我们大体对 React 组件的生命周期有一个了解了,下面我们通过 Demo 来直观的感觉一下。

4、实例演示组件的生命周期

经过上面的学习,我们大体对 React 组件的生命周期有了一定的认识,下面我们写一个 Demo 来验证一下。

我们可以使用前面学过的知识使用 yarn + webpack + ES6 来创建项目,如果不懂这些知识,可以看看前面相关的章节。以下 Demo 是在 mac 环境下开发的。

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(){
     // 这里卸载父组件也会导致卸载子组件
     ReactDOM.unmountComponentAtNode(document.getElementById("container"));
   }

/**
 * 通过修改 state 来修改 props 用来测试 componentWillReceiveProps 方法
 */
   changeState(){
     this.setState({
       name:'TigerChain11111'
     })
   }

}


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

在这里我一口气写完了,注释非常详细,如果你学习过前面章节的知识,那么这个很容易看懂。

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'
    }
  }
  /**
   * 在挂载之前调用
   */
  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() ;
  }

  /**
   * 在挂载之后调用
   */
  componentDidMount(){
    console.log("~~ componentDidMout ~~");
    alert("~~ componentDidMout ~~") ;
  }

  /**
   * 组件挂载之后 当调用 setState() 的时候  如果此方法返回 true ,则会重新渲染,否则不会
   */
  shouldComponentUpdate(nextProps, nextState){
      console.log("~~ shouldComponentUpdate ~~");
      console.log("shouldComponentUpdate nextState",nextState);
      alert("~~ shouldComponentUpdate ~~"+nextState) ;
      return true ;
  }

  /**
   * props 改变的时候调用
   */
  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 ~~") ;
  }

  /**
   * 组件已经更新
   */
  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 这一节。

6、在项目根目录新建 .babelrc 文件并输入以下内容

{
  "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",//本地服务器所加载的页面所在的目录
    historyApiFallback: true,//不跳转
    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 组件的生命周期。我们回过头再去看前面的生命周期图,就能很好的理解了。请大家务必照着 demo 敲一遍代码,以便加深理解。(老鸟直接略过)

到此为止,我们的 React 组件的生命周期就讲完了。

如果喜欢,就点个喜欢吧。

Demo 地址

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

上一篇 下一篇

猜你喜欢

热点阅读