挂载阶段

  constructor -> static getDerivedStateFromProps ->  render -> componentDidMount

  constructor(构造函数):初始化状态,当然它还接受一个props参数,可以使用组件传递过来的props,通常是用props初始化state。

  getDerivedStateFromProps: 被static 修饰,静态方法,这也意味着,在函数里面不能使用this和实例方法。它接受两个参数 props 和state,在渲染之前,根据props计算得到state,并返回state。

  render(渲染):组件中render 函数,它是至关重要的,因为组件的目的就是要渲染内容到页面上,不过它返回是一个虚拟DOM, ReactDOM 根据它构建出真实的DOM渲染到页面上。它会根据props 和state 渲染出react element, 指导react渲染出真正的dom. 但总存在特殊的情况,组件不需要渲染什么东西,如验证用户有没有登录的组件,它确实不需要返回什么,我们只是根据它进行跳转到不同的页面,这时直接在render 函数中返回null.

  componentDidMount(挂载完成):当真实的DOM 渲染到页面上会触发它。 需要注意的是render 函数在调用完成后,componentDidMount 并不会立刻调用,而是在当所有组件的render函数都调用完华之后,每个组件的componentDidMount 才会调用。 写一下代码会看得比较清楚,这也是我第一次明白地认识了react的挂载生命周期。

  写一个Counter 和一个CounterWrapper 组件, CounterWrapper包含Counter 。CounterWrapper 为父组件,Counter 为子组件。为了更能清楚地明白生命周期函数,CounterWrapper组件多包含几个Counter. 为了对每一个Counter 进行区分,分别给它们传一个caption 和initValue 参数。 在CounterWrapper 中 由于没有state, 我只写了render函数和ComponentDidMount 函数,而在子组件Counter中,它有state, 有完整的生命周期函数,依次写了四个阶段,constructor, static  getDerivedStateFromProps, render, componentDidMount, 当然这里只是console.log一下信息,看一下执行顺序

// 子组件Counter
class Counter extends React.Component {
constructor(props) {
super(props);
console.log(`进入子组件Counter的构造函数constructor ----- ${props.caption}`);
this.state = {
count: props.initValue ||
}
} static getDerivedStateFromProps(props) {
console.log(`进入子组件Counter的getDerivatedStateFromProps ----- ${props.caption}`);
}
render() {
console.log(`进入子组件Counter的render ----- ${this.props.caption}`);
const buttonStyle = {
margin: '10px'
};
return (
<div>
          <button style={buttonStyle} >+</button>
<button style={buttonStyle} value={}>-</button>
<span>{this.props.caption}count: {this.state.count}</span>
</div>
);
}
componentDidMount() {
console.log(`进入子组件Counter的componentDidMount ----- ${this.props.caption}`);
}
} // 父组件CounterWrapper
class CounterWrapper extends React.Component {
render(){
console.log('进入父组件CounterWrapper的render 函数');
return (<div>
<Counter caption="第一个" initValue={}></Counter>
<Counter caption="第二个" initValue={}></Counter>
<Counter caption="第三个" initValue={}></Counter>
</div>)
}
componentDidMount() {
console.log('进入父组件CounterWrapper的 componentDidMount 函数');
}
}

  打开控制台,重点看一下componentDidMount。先进入的是父组件CounterWrapper 的render 函数,然后再进入第一个子组件的constructor, getDerivatedStateFromProps和 render, 再进入第二个子组件的constructor, getDerivatedStateFromProps和 render函数,再进入第三个子组件的constructor, getDerivatedStateFromProps和 render函数, 最后才是每一个子组件的componentDidMount, 第二个子组件的ccomponentDidMount函数, 第三个子组件的ccomponentDidMount函数,最后的最后是父组件的CompoentDidMount.

  组件的挂载生命周期并不是依次调用的,render 函数后面并不是紧紧根随着componentDidMount 函数。只有当三个组件的render函数都调用完成后,三个组件的componentDidMount 才连在一起被调用。 只有当所有的子组件的componentDidMount都调用了,父组件的componetDidMount 才会被调用。在componentDidMount 函数的调用上,我一直存在误解,以为render 函数调用后,立即执行它,并认为父组件的componentDidMount优于子组件的componentDidMount 执行,真是太想当然了。

  现在再来想一下为什么会有这样的设计,当使用componentDidMount 的时候,我们听得最多的一句话可能就是,在这里,你可以操作真实的DOM了,换句话说,当 组件compoentDidMount的时候,真实的DOM 已经渲染完毕了,整个页面都已经渲染完成了。整个页面就意味着整个DOM树都已经构建完成了,注意这里是整个DOM树。当React进入到组件的render 函数时,它只知道当前组件长什么样子,而不会知道整个DOM树长什么样子,所以它只能接着找到第二个组件render, 因为后面有第三个子组件,它还是不知道整个DOM树长什么样子,所以它还要找到第三个组件render,  也就是说它会把所有的组件都循环一遍,直到能够构建整个DOM树,它才会渲染真实的DOM, 这也是最为省事的办法,如果它找到一个渲染一个,后面的组件再对前面的组件有影响,它要把前面的做法再来一次,效率低下。一次渲染就OK了。 渲染之后,肯定是最深层的组件先完成,只有小的完成了才能组成大的,所以最深层的组件的componentDidMount 先执行, 最外层的最后执行。这让我们想成了JS事件处理阶段,当构建DOM树的过程中,它是捕获阶段,从外面找到最里面,而在渲染真实的DOM的时候,componentDidMount的时候,它是冒泡阶段, 从最里面到最外面。

  更新阶段

  static getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate

  getDerivedStateFromProps: 和挂载阶段用法是一致的, 它适应用一种情况:组件的状态一直受父组件props的影响, 具体看下面的实例,css 用的是bootstrap的,npm install bootstrap 或 直接cdn link。

// 子组件DirectionDisplay
export class DirectionDisplay extends React.Component {
state = {
direction: "up",
lastValue:
}
getClasses() {
return (this.state.direction === "up" ? "bg-success" : "bg-danger")
+ " text-white text-center p-2 m-2";
}
render() {
return <h5 className={this.getClasses()}>
{this.props.value}
</h5>
}
/*
接受props和state(当前组件的), 返回state. 当前组件的state只有两个属性lastValue, direction, 所以在函数返回state的时候,最好也返回这两个属性
这里要注意一点,使用if 判断,如果props没有变化的话,直接返回state,
因为update 阶段,也会调用这个生命周期函数。
*/
static getDerivedStateFromProps(props, state) {
if (props.value !== state.lastValue) {
return {
lastValue: props.value,
direction: state.lastValue > props.value ? "down" : "up"
}
}
return state;
}
} // 父组件
class App extends React.Component {
state = {counter: }
changeCounter = (val) => {
this.setState({ counter: this.state.counter + val })
}
render() {
return <div className="container text-center">
<DirectionDisplay value={this.state.counter} />
<div className="text-center">
<button className="btn btn-primary m-1"
onClick={() => this.changeCounter(-)}>Decrease</button>
<button className="btn btn-primary m-1"
onClick={() => this.changeCounter()}>Increase</button>
</div>
</div >
}
}

  shouldComponentUpdate() : 组件应不应该更新,它决定了一个组件是不是需要重新渲染, 如果它返回fasle, 就表示该组件不需要更新,也就不会重新渲染,它后面的生命周期函数就不会被执行。如果返回true,表示该组件需要更新, 它后面的生命周期函数才会被执行,重新渲染。 接受两个参数nextProps和nextState, 可以判断它们是不是和当前的props 和state 一致,如果一致,就是返回true,表示更新,如果不一致,则返回false,就不更新了。 现在来写一下componentShouldUpdate

    // 如果父组件传递过来的value发生变化,才会返回true, 组件才需要演染。
shouldComponentUpdate(nextProps, nextState) {
return (nextProps.value!== this.props.value);
}

  render 就是渲染组件了,这没有什么可说的。getSnapshotBeforeUpdate,在更新之前得到快照,在使用refs的时候会用到,一般也不会用到。  componentDidUpdate, 和componentDidMount 用法一致

  卸载阶段,

  componentwillUnmount 函数,当React 组件要从DOM树上删掉之前,对应的componentWillUnmount函数就会被调用,它适合做一些清理性的工作,就是删除这个组件之前有没有什么要清理的。注意它没有对应的did函数,因为组件删除以后,没有什么事情可以做了。

React 学习(四) ---- 生命周期函数的更多相关文章

  1. React学习笔记-生命周期函数

    定义: 生命周期函数指在某一个时刻组件会自动调用执行的函数

  2. 【React自制全家桶】五、React组件的生命周期函数详解

    一.总览React组件的生命周期函数 什么是生命周期函数:简单的来说就是 在某个时刻会自动执行的函数 二.React的生命周期函数主要由四块组成 分别是:组件初始化.组件挂载.组件更新.组件卸载 三. ...

  3. React——组件的生命周期函数

    每一个组件都有一些生命周期函数. 当组件实例被创建并且会插入到DOM中,下面这些函数会被调用 constructor componentWillMount render componentDidMou ...

  4. react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

    react学习小结   本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...

  5. React中的生命周期函数

    React的生命周期函数 什么是生命周期函数:生命周期函数是指在某一个时刻组件会自动调用执行的函数 Initialization:初始化 执行Constructor,初始state和props Mou ...

  6. 10. react 基础 ref 的使用 及 React 16 的生命周期函数 及 生命周期函数使用场景

    一. ref 的使用 ( 直接获取 DOM 元素 ) 在 input 标签上 可以使用 ref 属性 获取当前DOM节点 eg: import React , { Component, Fragmen ...

  7. react学习二 生命周期

    转自:https://www.cnblogs.com/gdsblog/p/7348375.html react 中compent getDefaultProps object getDefaultPr ...

  8. 【JAVASCRIPT】React学习-组件生命周期

    摘要 整理组件加载过程,详细见官方文档:https://facebook.github.io/react/docs/react-component.html mount 过程 1)constructo ...

  9. react学习(四)之设置 css样式 篇

    react中设置css样式 方法一: 行内样式:使用{{  }},与正常jsx中插入js代码不一样,这里需要两个括号. <div style={ { float: 'right',} }> ...

随机推荐

  1. JVM源码分析--ClassLoader类加载器

    本人原创,转载请注明出处:https://www.cnblogs.com/javallh/p/10224187.html 1.JDK已有类加载器: BootStrap ClassLoader (启动类 ...

  2. odoo学习总结

                                                   odoo10总结 1.odoo中的向导应用. .py文件 # -*- coding: utf-8 -*-f ...

  3. Wechart 饼图

    预览 Preview | Usage Source | Pie Source | Tutorial Wechart by Cax Cax 众所周知 Cax 既能开发游戏.又能开发图表.本文将从饼图开始 ...

  4. python2.x版本与python3.x版本的区别以及运算符

    python2.x中: 重复代码,语言不统一,不支持中文 py2中除法获取的都是整形 py2中有long(长整形) print 可以加括号也可以不加括号 range 在py2中打印的结果是列表 py2 ...

  5. Tarjan算法(缩点)

    因为最近在学2sat,需要学习前置技能—Tarjan算法,所以花了一天的时间学习这个算法 算法步骤: 1.从一个点开始dfs,并加入栈 2.如果下一个点没有到过,跳到第一步 3.如果下一个点到过,并且 ...

  6. Graph Without Long Directed Paths CodeForces - 1144F (dfs染色)

    You are given a connected undirected graph consisting of nn vertices and mm edges. There are no self ...

  7. Git文件冲突的常用解决方法

    在提交代码时,偶尔会有文件冲突的情况,当出现: Please, commit your changes or stash them before you can merge. 提示后,可用依次输入下列 ...

  8. final域的内存语义

    final 一.final的基本语义 final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量) 当用final修饰一个类时,表明这个类不能被继承. 当用final修饰一个方法时,表明这个方 ...

  9. React Native之获取通讯录信息并实现类通讯录列表(ios android)

    React Native之获取通讯录信息并实现类通讯录列表(ios android) 一,需求分析 1,获取通讯录信息,筛选出通讯录里有多少好友在使用某个应用. 2,获取通讯录信息,实现类通讯录,可拨 ...

  10. 使用PSR-4配合composer autoload 自动加载文件夹

    require 文件很麻烦,使用PSR-4搭配composer一次加载,终生受用. 感觉类似java中的import了,自己先记录一下最近理解的. 用composer管理自己的包吧 安装compose ...