React生命周期详解

来源:互联网 发布:交换机端口抓包 编辑:程序博客网 时间:2024/05/22 04:23

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