2018-10-28 22:49:18 WonderGlans 阅读数 144
  • 2019 react入门至高阶实战,含react hooks

    这是2019 react入门到高级新课程 学习react,不仅能带来技术提升,同时提高开发效率和体验,更能带来好的就业机会。 本课程主要分为以下几个部分:  一,前端工程化基础?  主要学习node和npm、yarn的基本用法  二,es6语法 学习必备的es6常用语法 。 三,react基础知识  学习如何搭建react项目,以及react组件,jsx语法、css处理方案、生命周期等基础知识。 并且根据这些知识开发一个个人网站。 四,react进阶知识?? 学习表单的处理,事件处理,Portals的使用,以及数据请求和API管理等进阶知识。 五,react高阶知识?? 学习react高级特性,react hooks,以及整个react生态体系的构成和应用 。 努力学习哟,带你精通react。

    1925 人正在学习 去看看 梁富城

React 16.3之前
在这里插入图片描述
1、getDefaultProps()
设置默认的props,也可以用dufaultProps设置组件的默认属性.

2、getInitialState()
在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state。此时可以访问this.props

3、componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。

4、 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。

5、componentDidMount()
组件渲染之后调用,只调用一次。

更新
6、componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。

7、shouldComponentUpdate(nextProps, nextState)
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候

8、componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state,但是不能调用this.setState

9、render()
组件渲染

10、componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。

卸载
11、componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
在这里插入图片描述

React16.3之后
在这里插入图片描述
最大的变动莫过于生命周期去掉了以下三个
componentWillMount
componentWillReceiveProps
componentWillUpdate

同时为了弥补失去上面三个周期的不足又加了两个
static getDerivedStateFromProps
getSnapshotBeforeUpdate
当然,这个更替是缓慢的,在整个16版本里都能无障碍的使用旧的三生命周期,但值得注意的是,旧的生命周期(unsafe)不能和新的生命周期同时出现在一个组件,否则会报错“你使用了一个不安全的生命周期”。

static getDerivedStateFromProps
会在初始化和update时触发,用于替换componentWillReceiveProps,可以用来控制 props 更新 state 的过程;它返回一个对象表示新的 state;如果不需要更新,返回 null 即可
getSnapshotBeforeUpdate
用于替换 componentWillUpdate,该函数会在update后 DOM 更新前被调用,用于读取最新的 DOM 数据,返回值将作为 componentDidUpdate 的第三个参数

2018-07-26 10:50:56 qq_30104281 阅读数 179
  • 2019 react入门至高阶实战,含react hooks

    这是2019 react入门到高级新课程 学习react,不仅能带来技术提升,同时提高开发效率和体验,更能带来好的就业机会。 本课程主要分为以下几个部分:  一,前端工程化基础?  主要学习node和npm、yarn的基本用法  二,es6语法 学习必备的es6常用语法 。 三,react基础知识  学习如何搭建react项目,以及react组件,jsx语法、css处理方案、生命周期等基础知识。 并且根据这些知识开发一个个人网站。 四,react进阶知识?? 学习表单的处理,事件处理,Portals的使用,以及数据请求和API管理等进阶知识。 五,react高阶知识?? 学习react高级特性,react hooks,以及整个react生态体系的构成和应用 。 努力学习哟,带你精通react。

    1925 人正在学习 去看看 梁富城

 

  • 初始化

1、getDefaultProps()

设置默认的props,也可以用dufaultProps设置组件的默认属性.

2、getInitialState()

在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state。此时可以访问this.props

3、componentWillMount()

组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。

4、 render()

react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。

5、componentDidMount()

组件渲染之后调用,只调用一次。

  • 更新

6、componentWillReceiveProps(nextProps)

组件初始化时不调用,组件接受新的props时调用。

7、shouldComponentUpdate(nextProps, nextState)

react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候,同样不能使用setState方法,同下边。

8、componentWillUpdata(nextProps, nextState)

组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state,此时修改state不应使用setState方法,否则会陷入死循环,应使用nextState.名称=要更改的内容,再次渲染就会使用更改后的值。

9、render()

组件渲染

10、componentDidUpdate()

组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。

  • 卸载

11、componentWillUnmount()

组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

转载: http://www.cnblogs.com/qiaojie/p/6135180.html

2018-11-15 10:04:33 qq_38045106 阅读数 169
  • 2019 react入门至高阶实战,含react hooks

    这是2019 react入门到高级新课程 学习react,不仅能带来技术提升,同时提高开发效率和体验,更能带来好的就业机会。 本课程主要分为以下几个部分:  一,前端工程化基础?  主要学习node和npm、yarn的基本用法  二,es6语法 学习必备的es6常用语法 。 三,react基础知识  学习如何搭建react项目,以及react组件,jsx语法、css处理方案、生命周期等基础知识。 并且根据这些知识开发一个个人网站。 四,react进阶知识?? 学习表单的处理,事件处理,Portals的使用,以及数据请求和API管理等进阶知识。 五,react高阶知识?? 学习react高级特性,react hooks,以及整个react生态体系的构成和应用 。 努力学习哟,带你精通react。

    1925 人正在学习 去看看 梁富城

生命周期的重要性,对于学习框架的重要性,就不多说了,下面主要讲一下react的生命周期中的这些钩子函数的基本用法。

话不多说,先上图:

react组件的构造

import React,{ Component } from 'react';//因为编译时要用到React,所以必须要引入

    class Demo extends Component {
      constructor(props,context) {
      super(props,context)//有constructor必须要supper,防止this报错
      this.state = {
          //定义组件的状态state
      }
    }
    componentWillMount () {
    }
    componentDidMount () {
    }
    componentWillReceiveProps (nextProps) {
    }
    shouldComponentUpdate (nextProps,nextState) {//必须要有返回值
    }
    componentWillUpdate (nextProps,nextState) {
    }
    componentDidUpdate (prevProps,prevState) {
    }
    render () {
    return (//最好加上()防止编译时遇到;自动插入的bug
        <div></div>
    )
    }
    componentWillUnmount () {
    }
}
export default Demo;

初始化(挂载)阶段

1.constructor(props,context)

接受父组件传过来的属性,并且可以初始化自己的state,构造器写了就要supper,防止this指向错误。

拓展:(在ES6的类中,每一个类都有一个contructor(构造器),当子类去继承父类的时候,父类的constructor需要执行一下,为子类去继承constructor中的一些东西,如果子类自己没有写constructor,默认的会生成一个constructor并且在其中就会执行弗雷的constructor,执行的方法就是super(),因为子类中的super就是父类的constructor

如果子类自己编写了constructor,那么就需要子类自己去super一次, 否则,子类的this将不被初始化,此时,子类的constructor就可以接收到外界传入的props,但是this上访问不到props,如果在constructor中需要使用到this.props,那么就必须在super中传入props,父类构造器就会为子类的this上挂载props)

2.componentWillMount() 

组件将要挂载

  1. 组件刚刚经过了constructor,数据的初始化完成
  2. 组件没有render,dom还没有渲染,不推荐写ajax请求

拓展:(虽然有些情况下并不会出错,但是如果ajax请求过来的数据是空,那么会影响页面的渲染,可能看到的就是空白。不利于服务端渲染,在同构的情况下,生命周期会到componentwillmount,这样使用ajax就会出错)

3.render()

插入jxs构成的dom结构(React会生成虚拟dom,然后利用diff算法进行对比,然后将改变的dom进行渲染吗,提高性能),render 函数并不做实际的渲染动作,它只是返回一个JSX描述的结构,最终由React来操作渲染过程,React会渲染render函数return的东西,如果return false  或者 null,就等于告诉React,不渲染任何东西。

4.componentDidMount()

组件已经渲染完成,dom节点生成,组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI,至此,初始化阶段完成

更新(运行中)阶段

1.componentWillReceiveProps(nextprops)

当前组件接受父组件的改变,重新经渲染组件时,接收一个nextprops(对比this.props和nextprops,然后setState当前组件的state,然后进行组件的重新渲染)参数。(nextprops为最新的props)

2.shouldComponentUpdate(nextprops,nextstate)

当组件state改变和componentWillReceiveProps(nextprops)后执行,react唯一用于组件重新渲染的生命周期(react中,当父组件的重新渲染会引起子组件的重新渲染,可以在该生命周期中进行判断,如return false  以阻止组件的更新,提高性能)。该生命周期一旦写在代码中,必须返回布尔值,return true或者false,代码才会继续执行,否则会报warning

3.componentWillUpdate(nextprops,nextstate)

组件将要重新渲染,不可以改数据(死循环)

4.render()

(上文已将讲过)

5.componentDidUpdate(prevprops,prevstate)

组件更新完成后进入该生命周期,类似于初始化阶段的componentDidMount(componentDidMount只会在第一次初始化完成后进入),参数中prevprops和prevsstate为组件更新前的props和state。

销毁(卸载)阶段

componentWillUnmount()

解除组件中的事件绑定(如onscroll),和一些定时器函数(如setTimeout和setInterval),和vue的销毁阶段类似。

小结:学习过react后,你会感受到react的灵活性,可以和vue对比学习,关于vue的生命周期,可参考我的另一篇博客

https://blog.csdn.net/qq_38045106/article/details/83717141

2019-07-17 17:26:30 huihuihaha222222 阅读数 30
  • 2019 react入门至高阶实战,含react hooks

    这是2019 react入门到高级新课程 学习react,不仅能带来技术提升,同时提高开发效率和体验,更能带来好的就业机会。 本课程主要分为以下几个部分:  一,前端工程化基础?  主要学习node和npm、yarn的基本用法  二,es6语法 学习必备的es6常用语法 。 三,react基础知识  学习如何搭建react项目,以及react组件,jsx语法、css处理方案、生命周期等基础知识。 并且根据这些知识开发一个个人网站。 四,react进阶知识?? 学习表单的处理,事件处理,Portals的使用,以及数据请求和API管理等进阶知识。 五,react高阶知识?? 学习react高级特性,react hooks,以及整个react生态体系的构成和应用 。 努力学习哟,带你精通react。

    1925 人正在学习 去看看 梁富城

react组件的生命周期:

  1. 生命周期指的是组件从初始化开始到结束的过程 , 或者是生命周期是描述react组件从开始到结束的过程。
  2. 每个react组件都具有生命周期。
  3. react都对组件通过生命周期给予的钩子函数进行管理。
钩子函数:
  • 指的是系统某些状态和参数发生改变的时候,系统立马去通知对应处理的函数,叫做钩子函数。通俗讲:一方面又变动。另一方面立马去处理
react组件经历的总阶段:
  1. mounted阶段 加载阶段 或者说初始化阶段 这个阶段组件由jsx转换成真实dom
  2. update阶段 组件运行中阶段 或者更新阶段 当组件修改自身状态,或者父组件修改子组件属性的时候发生的阶段。
  3. umount阶段 组件卸载阶段 这个一般是组件被浏览器回收的阶段。

初始化生命周期整体流程低版本:

  1. getDefaultProps 取得默认属性
  2. getInitialState 初始化状态
  3. componentWillMount 即将进入dom
  4. render 描画dom
  5. componentDidMount 已经进入dom

初始化生命周期整体流程高版本:
(执行顺序就是1.2.3)

  1. componentWillMount 即将进入dom
  2. render 描画dom
  3. componentDidMount 已经进入dom
  • will和did都可以写交互,官方推荐did
class App extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return (
          <div>
            <h2 ref="tit">生命周期</h2>
          </div>
        );
      }
      componentWillMount() {
        console.log(this.refs.tit); //undefined
      }
      componentDidMount() {
        console.log(this.refs.tit); //<h2>生命周期</h2>
      }
    }
    ReactDOM.render(<App />, document.getElementById("out"));

具体的声明函数周期—运行中阶段 数据更新过程:

(运行中阶段只有在父组件修改了子组件的属性或者说一个组件修改自身的状态才会发生的情况

  1. 组件将要接受新值componentWillReceiveProps(已加载组件收到新的参数时调用)
 class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          info: ""
        };
      }
      render() {
        return (
          <div>
            <h2 ref="tit">父组件</h2>
            <button onClick={this.tap.bind(this)}>获取dom元素</button>
            <input type="text" ref="ipt" />
            <button onClick={this.send.bind(this)}>发送给子组件</button>
            <hr />
            <Child name={this.state.info} />
          </div>
        );
      }
      tap() {
        console.log(this.refs.tit.innerHTML);
      }
      send() {
        this.setState({
          info: this.refs.ipt.value
        });
      }
    }
    class Child extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return (
          <div>
            <div>子组件</div>
            <p>接收父组件发送的数据--{this.props.name}</p>
          </div>
        );
      }
      componentWillReceiveProps(a) {
        console.log(a); //也是跟(跟父传给子的值相关)
        //父组件接受子组件的参数时会触发
        console.log("componentWillReceiveProps"); //componentWillReceiveProps
      }
      shouldComponentUpdate(a) {
        //should函数不写的情况下,默认是允许更新
        console.log(a); //这个参数跟更新的数据值相关,当componentWillReceiveProps函数触发时,参数a值为{name: "111"}(跟父传给子的值相关)
        if (a.name == "hello") {
          //根据这个参数值可以做判断(可以避免不必要的更新)
          return true;
        } else {
          return false;
        }
        // return true;
        //false时 不允许视图更新 componentWillUpdate,componentDidUpdate不会触发
      }
      componentWillUpdate() {
        console.log("componentWillUpdate"); //componentWillUpdate 当点击事件触发状态被修改时触发
      }
      componentDidUpdate() {
        console.log("componentDidUpdate"); //componentDidUpdate 当点击事件触发状态被修改时触发
      }
    }
    ReactDOM.render(<App />, document.getElementById("out"));
    // 父组件-子组件:
    // 在子组件标签上绑定属性名,值为父组件需要传递的状态值,子组件内部通过this.props.name接收。
  1. 组件是否更新 shouldComponentUpdate (影响整个项目的性能,决定视图的更新)
  2. 组件即将更新componentWillUpdate
  3. 必不可少的render
  4. 组件更新完毕时运行的函数 componentDidUpdate
class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          str: "hello"
        };
      }
      render() {
        return (
          <div>
            <h2 ref="tit">生命周期</h2>
            <p>{this.state.str}</p>
            <button onClick={this.tap.bind(this)}>修改S</button>
          </div>
        );
      }
      tap() {
        this.setState({ str: "nihao" });
      }
      componentWillMount() {
        console.log(this.refs.tit); //undefined
      }
      componentDidMount() {
        console.log(this.refs.tit); //<h2>生命周期</h2>
      }

      componentWillReceiveProps() {
        //父组件接受子组件的参数时会触发
        console.log("componentWillReceiveProps");
      }
      shouldComponentUpdate(a) {
        //should函数不写的情况下,默认是允许更新
        console.log(a); //这个参数跟更新的数据值相关
        return true;
        //false时 不允许视图更新 componentWillUpdate,componentDidUpdate不会触发
      }
      componentWillUpdate() {
        console.log("componentWillUpdate"); //componentWillUpdate 当点击事件触发状态被修改时触发
      }
      componentDidUpdate() {
        console.log("componentDidUpdate"); //componentDidUpdate 当点击事件触发状态被修改时触发
      }
    }
    ReactDOM.render(<App />, document.getElementById("out"));

销毁时 componentWillUnmount

  • 卸载组件 ReactDOM.unmountComponentAtNode(‘节点’)
<button onClick={this.tap1.bind(this)}>销毁</button>

tap1() {
        ReactDOM.unmountComponentAtNode(document.getElementById("out"));
        //组件完全被浏览器回收,清空
      }
2018-10-26 14:45:17 weixin_42186513 阅读数 1023
  • 2019 react入门至高阶实战,含react hooks

    这是2019 react入门到高级新课程 学习react,不仅能带来技术提升,同时提高开发效率和体验,更能带来好的就业机会。 本课程主要分为以下几个部分:  一,前端工程化基础?  主要学习node和npm、yarn的基本用法  二,es6语法 学习必备的es6常用语法 。 三,react基础知识  学习如何搭建react项目,以及react组件,jsx语法、css处理方案、生命周期等基础知识。 并且根据这些知识开发一个个人网站。 四,react进阶知识?? 学习表单的处理,事件处理,Portals的使用,以及数据请求和API管理等进阶知识。 五,react高阶知识?? 学习react高级特性,react hooks,以及整个react生态体系的构成和应用 。 努力学习哟,带你精通react。

    1925 人正在学习 去看看 梁富城

react生命周期理解

渲染的过程

react 生命周期在不同状态下的执行顺序

  • 当首次装载组件时,按顺序执行 getDefaultProps、getInitialState、componentWillMount、render 和 componentDidMount;

  • 当卸载组件时,执行 componentWillUnmount;

  • 当重新装载组件时,此时按顺序执行 getInitialState、componentWillMount、render 和 componentDidMount,但并不执行 getDefaultProps;

  • 当再次渲染组件时,组件接受到更新状态,此时按顺序执行 componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate。

疑问

  • 为何 React 会按上述顺序执行生命周期?

  • 为何 React 多次 render 时,会执行生命周期的不同阶段?

  • 为何 getDefaultProps 只执行了1次?

详解

自定义组件的生命周期主要通过三种状态进行管理:MOUNTING,RECIVE_PROPS,UNMOUNTING;他们负责通知组件当前所处的状态,应该执行生命周期中的哪个步骤,是否可以更新 state 。
三个状态对应三种方法:

  • MOUNTING -> mountComponent
  • RECIVE_PROPS -> updateComponent
  • UNMOUNTING -> unmountComponent

每个方法都提供了两种处理方法,will 在进入状态之前调用,did 在进入状态之后调用

createClass 创建自定义组件

createClass 创建自定义组件的入口方法,负责管理生命周期中的 getDefaultProps。getDefaultProps() 只执行一次,这样所有实例初始化的 props 将会共享。

通过 createClass 创建自定义组件,利用原型继承 ReactCompositeComponentBase 父类,按顺序合并 mixins,设置初始化 defaultProps,创建元素ReactElement.

当使用 ES6 classes 编写 React 组件时,其实就是调用内部方法 createClass 创建组件, 该方法返回一个Constructor(props, context, updater) 用来生成组件实例,我们发现在调用React.createClass,已经执行了getDefaultProps() 和 getInitialState() ,并将其赋值于Constructor的原型中

// ReactCompositeComponent 的基类
var ReactCompositeComponentBase = function() {};

// 将 Mixin 合并到 ReactCompositeComponentBase 的原型上
assign(
  ReactCompositeComponentBase.prototype,
  ReactComponent.Mixin,
  ReactOwner.Mixin,
  ReactPropTransferer.Mixin,
  ReactCompositeComponentMixin
);

var ReactCompositeComponent = {
  LifeCycle: CompositeLifeCycle,
  Base: ReactCompositeComponentBase,

  // 创建组件
  createClass: function(spec) {
    // 构造函数
    var Constructor = function(props, context) {
      this.props = props;
      this.context = context;
      this.state = null;
      var initialState = this.getInitialState ? this.getInitialState() : null;
      this.state = initialState;
    };

    // 原型继承父类
    Constructor.prototype = new ReactCompositeComponentBase();
    Constructor.prototype.constructor = Constructor;

    // 合并 mixins
    injectedMixins.forEach(
      mixSpecIntoComponent.bind(null, Constructor)
    );
    mixSpecIntoComponent(Constructor, spec);

    // mixins 合并后装载 defaultProps (React整个生命周期中 getDefaultProps 只执行一次)
    if (Constructor.getDefaultProps) {
      Constructor.defaultProps = Constructor.getDefaultProps();
    }

    for (var methodName in ReactCompositeComponentInterface) {
      if (!Constructor.prototype[methodName]) {
        Constructor.prototype[methodName] = null;
      }
    }

    return ReactElement.createFactory(Constructor);
  }
}

状态一 MOUNTING

mountComponent 负责管理生命周期中的 getInitialState、componentWillMount、render 和 componentDidMount。

由于 getDefaultProps 是通过 Constrouctor 进行管理,因此也是整个生命周期中最先开始执行的。mountComponent 无法调用到 getDefaultProps ,所以getDefaultProps 只执行一次。

由于通过 ReactCompositeComponentBase 返回的是一个虚拟节点,因此需要利用 instantiateReactComponent 去得到实例,再使用 mountComponent 拿到结果作为当前自定义元素的结果。

首先通过 mountComponent 装载组件,此时,将状态设置为 MOUNTING ,利用 getInitialState 获取初始 state, 初始化更新队列。

若存在 componentWillMount ,则执行。如果此时在 componentWillMount 中调用 setState 是不会触发 reRender, 而是进行 state 合并。

到此时,已经完成 MOUNTING 的工作,更新状态为 NULL,同时 state 也将执行更新操作,此刻在 render 中可以获取更新后的 this.state 数据。

其实,mountComponent 本质上是通过 递归渲染 内容的,由于递归的特性,父组件的 componentWillMount 一定在其子组件的 componentWillMount 之前调用,而父组件的 componentDidMount 肯定在其子组件的 componentDidMount 之后调用。

当渲染完成之后,若存在 componentDidMount 则触发。这就解释了 componentWillMount - render - componentDidMount 三者之间的执行顺序。

// 装载组件
mountComponent: function(rootID, transaction, mountDepth) {
  // 当前状态为 MOUNTING
  this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;

  // 当前元素对应的上下文
  this.context = this._processContext(this._currentElement._context);

  // 当前元素对应的 props
  this.props = this._processProps(this.props);

  // 获取初始化 state
  this.state = this.getInitialState();

  // 初始化更新队列
  this._pendingState = null;
  this._pendingForceUpdate = false;

  // componentWillMount 调用setstate,不会触发rerender而是自动提前合并
  if (this.componentWillMount) {
    this.componentWillMount();
    if (this._pendingState) {
      this.state = this._pendingState;
      this._pendingState = null;
    }
  }

  // 得到 _currentElement 对应的 component 类实例
  this._renderedComponent = instantiateReactComponent(
    this._renderValidatedComponent(),
    this._currentElement.type
  );

  // 完成 MOUNTING,更新 state
  this._compositeLifeCycleState = null;

  // render 递归渲染
  var markup = this._renderedComponent.mountComponent(
    rootID,
    transaction,
    mountDepth + 1
  );

  // 如果存在 this.componentDidMount,则渲染完成后触发
  if (this.componentDidMount) {
    transaction.getReactMountReady().enqueue(this.componentDidMount, this);
  }

  return markup;
}

状态二:RECEIVE_PROPS

updateComponent 负责管理生命周期中的 componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate。

首先通过 updateComponent 更新组件,如果前后元素不一致说明组件需要更新,此时将状态更新为 RECEIVE_PROPS。

如果存在 componentWillReceiveProps,则执行。如果此时在 componentWillReceiveProps 中调用 setState ,不会触发 reRender ,只会合并 state。

到此时,已经完成 RECEIVE_PROPS ,更新状态为 null ,同时 state 也将执行更新操作,此时调用 this.state 会获取到更新后的 数据。

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

调用 shouldComponentUpdate 判断是否需要进行组件更新,如果存在 componentWillUpdate,则执行。

updateComponent 本质上也是通过 递归渲染 内容的,由于递归的特性,父组件的 componentWillUpdate 一定在其子组件的 componentWillUpdate 之前调用,而父组件的 componentDidUpdate 肯定在其子组件 componentDidUpdate 之后调用。

当渲染完成之后,若存在 componentDidUpdate ,则执行。这就解释了 componentWillReceiveProps - componentWillUpdate - render - componentDidUpdate 它们之间的执行顺序。

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

// 更新组件
updateComponent: function(transaction, prevParentElement, nextParentElement) {
  var prevContext = this.context;
  var prevProps = this.props;
  var nextContext = prevContext;
  var nextProps = prevProps;

  if (prevParentElement !== nextParentElement) {
    nextContext = this._processContext(nextParentElement._context);
    nextProps = this._processProps(nextParentElement.props);
    // 当前状态为 RECEIVING_PROPS
    this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;

    // 如果存在 componentWillReceiveProps,则执行
    if (this.componentWillReceiveProps) {
      this.componentWillReceiveProps(nextProps, nextContext);
    }
  }

  // 设置状态为 null,更新 state
  this._compositeLifeCycleState = null;
  var nextState = this._pendingState || this.state;
  this._pendingState = null;
  var shouldUpdate =
    this._pendingForceUpdate ||
    !this.shouldComponentUpdate ||
    this.shouldComponentUpdate(nextProps, nextState, nextContext);
  if (!shouldUpdate) {
    // 如果确定组件不更新,仍然要设置 props 和 state
    this._currentElement = nextParentElement;
    this.props = nextProps;
    this.state = nextState;
    this.context = nextContext;
    this._owner = nextParentElement._owner;
    return;
  }
  this._pendingForceUpdate = false;

  ......

  // 如果存在 componentWillUpdate,则触发
  if (this.componentWillUpdate) {
    this.componentWillUpdate(nextProps, nextState, nextContext);
  }

  // render 递归渲染
  var nextMarkup = this._renderedComponent.mountComponent(
    thisID,
    transaction,
    this._mountDepth + 1
  );

  // 如果存在 componentDidUpdate,则触发
  if (this.componentDidUpdate) {
    transaction.getReactMountReady().enqueue(
      this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
      this
    );
  }
}

状态三:UNMOUNTING

unmountComponent 负责管理生命周期中的 componentWillUnmount。

首先将状态设置为 UNMOUNTING,若存在 componentWillUnmount,则执行;如果此时在 componentWillUnmount 中调用 setState,是不会触发 reRender,因为所有更新队列和更新状态都被重置为 NULL,完成了组件卸载操作。

// 卸载组件
unmountComponent: function() {
  // 设置状态为 UNMOUNTING
  this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;

  // 如果存在 componentWillUnmount,则触发
  if (this.componentWillUnmount) {
    this.componentWillUnmount();
  }

  // 更新状态为 null
  this._compositeLifeCycleState = null;
  this._renderedComponent.unmountComponent();
  this._renderedComponent = null;

  ReactComponent.Mixin.unmountComponent.call(this);
}

setState 更新机制

当调用 setState 时,会对 state 以及 _pendingState 更新队列进行合并操作,但其实真正更新 state 的幕后黑手是 replaceState。

replaceState 会先判断当前状态是否为 MOUNTING,如果不是即会调用ReactUpdates.enqueueUpdate 执行更新。

当状态不为 MOUNTING 或 RECEIVING_PROPS 时,performUpdateIfNecessary 会获取 _pendingElement、_pendingState、_pendingForceUpdate,并调用 updateComponent 进行组件更新。

如果在 shouldComponentUpdate 或 componentWillUpdate 中调用 setState,此时的状态已经从 RECEIVING_PROPS -> NULL,则 performUpdateIfNecessary 就会调用 updateComponent 进行组件更新,但 updateComponent 又会调用 shouldComponentUpdate 和 componentWillUpdate,因此造成循环调用,使得浏览器内存占满后崩溃。

// 更新 state
replaceState: function(completeState, callback) {
  validateLifeCycleOnReplaceState(this);

  // 更新队列
  this._pendingState = completeState;

  // 判断状态是否为 MOUNTING,如果不是,即可执行更新
  if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
    ReactUpdates.enqueueUpdate(this, callback);
  }
},

// 如果存在 _pendingElement、_pendingState、_pendingForceUpdate,则更新组件
performUpdateIfNecessary: function(transaction) {
  var compositeLifeCycleState = this._compositeLifeCycleState;

  // 当状态为 MOUNTING 或 RECEIVING_PROPS时,则不更新
  if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
      compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
    return;
  }

  var prevElement = this._currentElement;
  var nextElement = prevElement;
  if (this._pendingElement != null) {
    nextElement = this._pendingElement;
    this._pendingElement = null;
  }

  // 调用 updateComponent
  this.updateComponent(
    transaction,
    prevElement,
    nextElement
  );
}

总结

  • React 通过三种状态:MOUNTING、RECEIVE_PROPS、UNMOUNTING,管理整个生命周期的执行顺序;

  • setState 会先进行 _pendingState 更新队列的合并操作,不会立刻 reRender,因此是异步操作,且通过判断状态(MOUNTING、RECEIVE_PROPS)来控制 reRender 的时机;

  • 不建议在 getDefaultProps、getInitialState、shouldComponentUpdate、componentWillUpdate、render 和 componentWillUnmount 中调用 setState,特别注意:不能在 shouldComponentUpdate 和 componentWillUpdate 中调用 setState,会导致循环调用。

react 生命周期

阅读数 1403

React的生命周期

阅读数 34

没有更多推荐了,返回首页