React生命周期详解

React 摒弃了十分消耗性能的手动DOM操作,通过控制组件state和props的改变 利用 diff算法 改变DOM,当DOM需要变动,都会先在虚拟DOM上发生,将实际发生变动的部分渲染在真实的DOM上,这样能极大的提高性能
React 中的组件本质上可以理解为是一个状态机,将状态和输出一一对应,这样可以比较直观的反应程序在不同状态时,对应什么样的输出.

组件的 生命周期 由3个部分组成:初始化阶段,运行中阶段,销毁阶段,每个阶段React都提供了不同的钩子函数供开发者使用

初始化阶段

  • getDefaultProps 初始化组件属性的默认值,只调用一次 , 该方法返回一个对象并缓存起来。然后与父组件指定的 props 对象合并,最后赋值给 this.props 作为该组件的默认属性
  • getInitialState 初始化每个实例的状态 , 初始化组件的 state 的值。其返回值会赋值给组件的 this.state 属性
  • componentWillMount 组件render之前,可以修改状态.如果此时在 componentWillMount 中调用 setState,是不会触发 reRender,而是进行 state 合并
  • render 根据 state 的值,生成页面需要的虚拟 DOM 结构,并返回该结构
  • componentDidMount 在render完成后 组件渲染到页面时触发 , 对根据虚拟 DOM 结构而生的真实 DOM 进行相应的处理。组件内部可以通过 ReactDOM.findDOMNode(this) 来获取当前组件的节点,然后就可以像 Web 开发中那样操作里面的 DOM 元素了

state属性介绍:
它是用来存储组件自身需要的数据。它是可以改变的,它的每次改变都会引发组件的更新。这也是 ReactJS 中的关键点之一。
即每次数据的更新都是通过修改 state 属性的值,然后 ReactJS 内部会监听 state 属性的变化,一旦发生变化,就会触发组件的 render 方法来更新 DOM 结构。

运行中阶段

  • componentWillReceiveProps 当组件接收到新的 props 时,会触发该函数。在改函数中,通常可以调用 this.setState 方法来完成对 state 的修改。如果此时在 componentWillReceiveProps 中调用 setState,是不会触发 reRender,而是进行 state 合并
  • shouldComponentUpdate 该方法用来拦截新的 props 或 state,然后根据事先设定好的判断逻辑,做出最后要不要更新组件的决定。
  • componentWillUpdate 当上面的方法拦截返回 true 的时候,就可以在该方法中做一些更新之前的操作,进行渲染之前触发 但它不能修改props和state
  • render 根据一系列的 diff 算法,生成需要更新的虚拟 DOM 数据。(注意:在 render 中最好只做数据和模板的组合,不应进行 state 等逻辑的修改,这样组件结构更加清晰)
  • componentDidUpdate 该方法在组件的更新已经同步到 DOM 中去后触发,我们常在该方法中做一 DOM 操作

注意:此时 this.state 虽然获取到更新数据,但只能在内部源码中使用,我们在开发时,若在 componentWillReceiveProps 中调用 setState,那么在 componentWillReceiveProps、shouldComponentUpdate 和 componentWillUpdate 中还是无法获取到更新后的 this.state,即此时访问的this.state 仍然是未更新的数据,只有在 render 和 componentDidUpdate 中才能获取到更新后的this.state。


注意:禁止在 shouldComponentUpdate 和 componentWillUpdate 中调用 setState,会造成循环调用,直至耗光浏览器内存后崩溃。

销毁阶段

  • componentWillUnmount 在销毁操作真正执行之前调用,我们通常会做一些取消事件绑定、移除虚拟 DOM 中对应的组件数据结构、销毁一些无效的定时器等工作。这些事情都可以在这个方法中处理。

示例代码

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

可以用下面这张图,来详细说明 React 组件生命周期中钩子函数 的触发顺序

react生命周期

初始化简单的实例

var MyFirstComponent = React.createClass({
  // 只调用一次,实例之间共享引用
  getDefaultProps: function () {
    // 下面的console.log()是在实例化组件时就被调用
    console.log('getDefaultProps, 1'); 
    return {name: 'Tom'};
  },

  // 初始化每个实例特有的状态
  getInitialState: function () {
    console.log('getInitialState, 2');
    return {ready: false};
  },

  // render之前最后一次修改状态的机会
  componentWillMount: function () {
    console.log('componentWillMount, 3');
    this.setState({ready: true});
  },

  // 只能访问this.props和this.state,只有一个顶层组件,不可以修改状态和DOM输出
  render: function () {
    console.log('render, 4');
    return (
      <p ref="textNode">
        Hello, {this.props.name ? this.props.name : 'World'}
        <br/>
        {'' + this.state.ready}
      </p>
    )
  },

  // 成功render并渲染完成真实DOM之后触发,可以修改DOM
  componentDidMount: function () {
    console.log('componentDidMount, 5');
  }
});

ReactDOM.render(
  <MyFirstComponent />,
  document.getElementById('example')
);

控制台显示的结果如下,可以很直观的看到各个函数的执行顺序
这里写图片描述

运行简单例子

var ChildComponent = React.createClass({
  // 组件将要接受到属性时触发
  componentWillReceiveProps: function () {
    console.log('componentWillReceiveProps 1');
  },

  // 组件是否需要更新,返回false则阻止render调用
  // 这个函数我们一般谨慎使用,只有在性能调优时会使用
  shouldComponentUpdate: function () {
    console.log('shouldComponentUpdate 2');
    return true;
  },

  // 组件接收到新的props或者state后,进行渲染之前触发
  // 但它不能修改props和state
  componentWillUpdate: function () {
    console.log('componentWillUpdate 3');
  },

  render: function () {
    console.log('render, 4');
    return (
      <p ref="myText">
        Hello, {this.props.name ? this.props.name : 'World'}
      </p>
    )
  },

  // 在render完成后 组件完成更新渲染到页面时触发
  componentDidUpdate: function () {
    console.log('componentDidUpdate 5');
    // 为了演示方便,这里使用了jQuery,需要在HTML中先加载jQuery库
    $(this.refs.myText).append("\nI'm here!");
  }
});

var ParentComponent = React.createClass({
  // 初始化状态
  getInitialState: function () {
    return {name: ''}
  },

  handleChange: function (event) {
    this.setState({name: event.target.value});
  },

  render: function () {
    return (
      <div>
        <ChildComponent name={this.state.name} />
        <input className="form-control" type="text" onChange={this.handleChange} />
      </div>
    );
  }
});

ReactDOM.render(
  <ParentComponent />,
  document.getElementById('example')
);

这里写图片描述

参考资料(https://facebook.github.io/react/docs/react-component.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值