挂载阶段

  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. Java NIO:IO与NIO的区别

    一.概念 NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多.在Java API中提供了两套N ...

  2. 几种content-type提交以及$_POST 和php://input

    在表单提交数据时,需要告诉服务端自己的content-type,好让服务端处理. 默认表单提交是x-www-form-urlencoded,还有一种常见的 multipart/form-data.那这 ...

  3. Java获取文件Content-Type的四种方法

    HTTP Content-Type在线工具 有时候我们需要获取本地文件的Content-Type,已知 Jdk 自带了三种方式来获取文件类型. 另外还有第三方包 Magic 也提供了API.Magic ...

  4. Mysql字段名与保留字冲突导致的异常解决

    一:引言 用hibernate建表时经常遇到的一个异常:Error executing DDL via JDBC Statement 方法: 查看报错sql语句.问题就在这里. 我是表名(字段名)与保 ...

  5. Redis系列文章总结:ASP.Net Core 中如何借助CSRedis实现一个安全高效的分布式锁

    引言:最近回头看了看开发的.Net Core 2.1项目的复盘总结,其中在多处用到Redis实现的分布式锁,虽然在OnResultExecuting方法中做了防止死锁的处理,但在某些场景下还是会发生死 ...

  6. SAI窗口无法移动

    昨天开SAI遇到了一个很奇怪的问题,改变了双屏的位置后SAI的窗口不能移动两边也有黑边,貌似是这样,标题栏只能进行上下改变窗口大小,不能移动窗体 问题是这样出现的:把任务栏解除锁定拖到侧边就会这样 解 ...

  7. 类装饰器,元类,垃圾回收GC,内建属性、内建方法,集合,functools模块,常见模块

    '''''''''类装饰器'''class Test(): def __init__(self,func): print('---初始化---') print('func name is %s'%fu ...

  8. Unique Snowflakes UVA - 11572 (离散化+尺取法)

    Emily the entrepreneur has a cool business idea: packaging and selling snowflakes. She has devised a ...

  9. iframe跨域解决方案

    公司某个功能用的是iframe,由于跨域的原因,我们不能直接设置父级页面iframe的高度,所以用了一个中间页home来完成父级页面iframe的高度设置,这种中间页其实很多时候不好用,因为涉及到页面 ...

  10. 远程调用HBase出错,尝试10次后,报org.apache.hadoop.hbase.MasterNotRunningException错误

    网上的解决方案挺多的,但都不适用于我今天下午碰到的情况. 环 境:HBase-0.90.3在debian 6下,客户端在windows上.我用之前的HBase服务器是没问题的,但重新解压并配置后就有问 ...