挂载阶段

  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. 江苏省选2019Round1游记

    JSOI2019R1过去了. Day0 打板子.看白书. 晚上太热了,楼下还在打铁,睡不着. 折腾到好晚才勉强睡着. Day1 早上好困啊. 开T1.看起来T1的60分很可做的样子?5min打完了(为 ...

  2. UVA10838 The Pawn Chess

    UVA好题没人写系列,感觉可以稍稍练习一下面向对象编程的形式(大雾) 题意很简单,在国际象棋的棋盘中有一些兵,走到对方底线即为胜利,问最优决策下谁能获胜.并输出最小步数. 首先这里的棋盘都只有\(4\ ...

  3. jdk1.8之线程中断

    在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止.中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断 " 线程中断不会使线 ...

  4. 关于NETCORE中的捆绑与最小化 以及与CDN连用

    参考文档:MSDN   Bundling and minification in ASP.NET Core 细说ASP.NET Core静态文件的缓存方式

  5. 开源后的.Net 如何选择使用

     .NET是跨平台的开发栈.它有一个标准库,称为.NET Standard Library,其中包含了大量的APIs.这个标准库由各种.NET运行环境实现:.NET Framework..NET Co ...

  6. java 接口实现防盗门功能

    Door: package locker; public abstract class Door { public abstract void open(); public abstract void ...

  7. 1076E - Vasya and a Tree(图的遍历)

    题意:给出一棵根节点为1的树,执行m次修改操作,每次修改为a,b,c,表示a节点的子树中,距离a小于等于b的子节点的权值加上c,求m次操作后每个节点的权值 分析:用线段树维护每层节点的权值,然后dfs ...

  8. plw的晚餐(毒瘤题害我暴0)

    题意 描述 plw吃完午饭之后,马上又觉得肚子饿了.他决定马上从美食区离开,赶往下一个吃饭地点"香香鸡".但是在plw离开离开美食区之前,需要按美食区的规矩画一个特殊符号,并且如果 ...

  9. Mysql数据库触发器调用脚本

    一.数据库触发器 mysql触发器trigger 实例详解 对数据库触发器new和old的理解 示例 二.UDF mySql的UDF是什么 三.安装执行命令UDF mysql触发器调用外部脚本(安装) ...

  10. TCP粘包问题解析与解决

    一.粘包分析 作者本人在写一个FTP项目时,在文件的上传下载模块遇到了粘包问题.在网上找了一些解决办法,感觉对我情况都不好用,因此自己想了个比较好的解决办法,提供参考 1.1 粘包现象 在客户端与服务 ...