在开发React组件的过程中,我们经常会遇到这个问题:什么情况下组件会重新渲染?

当内部data发生改变,state发生改变(通过调用this.setState()) 以及父组件传过来的props发生改变时,会导致组件重新渲染。

以下几个问题同样值得我们思考:

setState()函数在任何情况下都会导致组件重渲染吗?如果setState中的state没有发生改变呢?

如果state和从父组件传过来的props都没变化,那他就一定不会发生重渲染吗?

首先,我们来解决这两个问题

没有导致state的值发生变化的this.setState()是否会导致重渲染  — 会

import React from 'react'

class Test extends React.Component{

constructor(props) {

super(props);

this.state = {

Number:1//设state中Number值为1

}

}

//这里调用了setState但是并没有改变setState中的值

handleClick = () => {

const preNumber = this.state.Number

this.setState({

Number:this.state.Number

})

}

render(){

//当render函数被调用时,打印当前的Number

console.log(this.state.Number)

return(

{this.state.Number}

)

}

}

从控制台的打印结果可以看出:共打印了15次1,但是组件并没有发生任何变化!!!

这样的结果不是我们想要的,如何阻止组件的重渲染呢?这时我们想到了React的一个生命周期钩子 shouldComponentUpdate

react生命周期中有这样一个钩子,叫shouldComponentUpdate函数,是重渲染时render()函数调用前被调用的函数,

两个参数 nextProps和nextState ,分别表示下一个props和state的值。

当函数返回false时,阻止接下来的render()函数的调用,阻止组件重渲染,返回true时,组件照常渲染

//加入shouldComponentUpdate钩子

//在render函数调用前判断:如果前后state中Number不变,通过return false阻止render调用

shouldComponentUpdate(nextProps,nextState){

if(nextState.Number == this.state.Number){

return false

}

}

加入上述代码后,打开控制台,点击按钮,还是白白的,说明无效的重渲染被我们阻止了

第二个问题,组件的state和从父组件传递过来的props都没改变,组件还会重渲染吗 — 可能

同样可以通过shouldComponentUpdate钩子进行阻止

所以说,前后不改变state的值的setState和无数据交换的父组件的重渲染都会导致组件的重渲染,但我们可以通过shouldComponentUpdate来阻止这两种情况

shouldComponentUpdate并不是完美的,只能阻止扁平的对象

nextState.Number == this.state.Number

如果调用层次比较深

nextState.NumberObject.number == this.state.NumberObject.number

Number 是一个数字变量

NumberObject是一个

数字变量(number类型)和

这时候,因为两者都指向堆中的同一个

对于number,string,boolean,undefined,null这些基本类型变量,值存在栈中

对于object,Array,function这些引用类型变量,引用存在栈中,而不同的引用却可以指向堆内存中的同一个

那么,问题就来了

怎么样才能取到不同的NumberObject呢?

四种方法:

1、ES6的扩展语法Object.assign()

2、深拷贝/浅拷贝或利用JSON.parse(JSON.stringify(data))相当于深拷贝,但使用受一定限制

3、引入immutable.

4、继承react的PureComponent组件(代替Component)

为了解决这种问题,出现了immutable对象,每次修改immutable对象都会创建一个新的不可变对象,而老的对象不会改变。

immutable.js主要有三大特性:

Persistent data structure (持久化数据结构)

structural sharing (结构共享)

support lazy operation (惰性操作)

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享

三个最重要的数据结构: Map List Set

Map:键值对集合,对应于 Object,ES6 也有专门的 Map 对象

List:有序可重复的列表,对应于 Array

Set:无序且不可重复的列表

//Map() 原生object转Map对象 (只会转换第一层,注意和fromJS区别)

immutable.Map({name:'danny', age:18})

//List() 原生array转List对象 (只会转换第一层,注意和fromJS区别)

immutable.List([1,2,3,4,5])

//fromJS() 原生js转immutable对象 (深度转换,会将内部嵌套的对象和数组全部转成immutable)

immutable.fromJS([1,2,3,4,5]) //将原生array --> List

immutable.fromJS({name:'danny', age:18}) //将原生object --> Map

//toJS() immutable对象转原生js (深度转换,会将内部嵌套的Map和List全部转换成原生js)

immutableData.toJS();

//查看List或者map大小

immutableData.size 或者 immutableData.count()

// is() 判断两个immutable对象是否相等

immutable.is(imA, imB);

//merge() 对象合并

var imA = immutable.fromJS({a:1,b:2});

var imA = immutable.fromJS({c:3});

var imC = imA.merge(imB);

console.log(imC.toJS()) //{a:1,b:2,c:3}

对于两个一样的数据,只有通过equals进行比较才是相等的  ==  ===都不行

如果 某个是另一个克隆出来的,那么全部都相等

push添加 unshift在头部添加 concat组合  返回的是新数据,而不是数据的长度

//增删改查(所有操作都会返回新的值,不会修改原来值)

var immutableData = immutable.fromJS({

a:1,

b:2,

c:{

d:3

}

});

var data1 = immutableData.get('a') // data1 = 1

var data2 = immutableData.getIn(['c', 'd']) // data2 = 3 getIn用于深层结构访问

var data3 = immutableData.set('a' , 2); // data3中的 a = 2

var data4 = immutableData.setIn(['c', 'd'], 4); //data4中的 d = 4

var data5 = immutableData.update('a',function(x){return x+4}) //data5中的 a = 5

var data6 = immutableData.updateIn(['c', 'd'],function(x){return x+4}) //data6中的 d = 7

var data7 = immutableData.delete('a') //data7中的 a 不存在

var data8 = immutableData.deleteIn(['c', 'd']) //data8中的 d 不存在复制代码

优点:

降低mutable带来的复杂度

节省内存

历史追溯性(时间旅行):时间旅行指的是,每时每刻的值都被保留了,想回退到哪一步只要简单的将数据取出就行,想一下如果现在页面有个撤销的操作,撤销前的数据被保留了,只需要取出就行,这个特性在redux或者flux中特别有用

拥抱函数式编程:immutable本来就是函数式编程的概念,纯函数式编程的特点就是,只要输入一致,输出必然一致,相比于面向对象,这样开发组件和调试更方便

缺点:

需要重新学习api

容易与原生对象混淆:由于api与原生不同,混用的话容易出错。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持

react htmlh1无效,详解react阻止无效重渲染的多种方式_而已_前端开发者相关推荐

  1. React Router路由详解

    React Router路由详解 一.基础 1.安装使用 2.React Router 中通用的组件 路由组件 BrowserRouter 和 HashRouter 路径匹配组件: Route 和 S ...

  2. android 回退函数,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 发布时间:2020-09-29 09:25:52 来源:脚本之家 阅读:137 作者:lqh 详解React Native监听A ...

  3. React 路由react-router-dom详解

    React 路由react-router-dom详解 ( 路由嵌套 + 路由传参 + 路由权限 + 路由优化 按需导入 + 404页面 ) 前面我们先了解一下 路由是什么? 路由分类有哪些?内置API ...

  4. 视频教程-React Hooks 案例详解(React 进阶必备)-其他

    React Hooks 案例详解(React 进阶必备) Leo 1978年8月生,河北石家庄人. 曾任职中软股份. 计算科学导师: 刘坤起博士. 开发的<电商分销系统>获得淘宝Top10 ...

  5. 回退监听android,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 前言 我们知道Android回退按键,会控制页面返回, 并且退出应用并非真正意义退出,仍在后台运行,所以在某些场景下需要监控an ...

  6. python open 打开是什么类型的文件-详解Python中open()函数指定文件打开方式的用法...

    文件打开方式 当我们用open()函数去打开文件的时候,有好几种打开的模式. 'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'- ...

  7. WebSocket安卓客户端实现详解(一)–连接建立与重连

    http://blog.csdn.net/zly921112/article/details/72973054 前言 这里特别说明下因为WebSocket服务端是公司线上项目所以这里url和具体协议我 ...

  8. tablewidget 行数自适应_PS滤镜知识:详解自适应广角滤镜的概括以及使用方式。...

    PS滤镜知识学习:详解自适应广角滤镜的概括以及使用方式."自适应广角"滤镜是Photoshop CS6中新增的滤镜,使用该滤镜可以拉直在使用广角镜头或鱼眼镜|头时产生的弯曲效果,也 ...

  9. python解释器在哪里_详解查看Python解释器路径的两种方式

    进入python的安装目录, 查看python解释器 进入bin目录 # ls python(看一下是否有python解释器版本) # pwd (查看当前目录) 复制当前目录即可 1. 通过脚本查看 ...

最新文章

  1. mysql $区别_mysql 与oracle区别
  2. BZOJ.4144.[AMPPZ2014]Petrol(Kruskal重构树)
  3. 【PC工具】图片批量添加水印工具,绿色免安装工具软件,妈妈再也不用担心我.....
  4. sizzle分析记录:getAttribute和getAttributeNode
  5. 用JavaScript实现2+2=5的奥秘
  6. python开发跟淘宝有联系没_Python爬取淘宝店铺和评论
  7. c语言为什么运行慢,【图片】今天写几个性能测试,为什么C语言跑得这么慢呢??【c语言吧】_百度贴吧...
  8. 清理服务器挖矿木马病毒
  9. red5 1.0.7 集成tomcat 并且 进行整合 官方例子oflaDemo
  10. C语言编程学习制作最好玩的报数游戏
  11. 论机器学习中数据的重要性
  12. linux 关闭系统中多余的服务
  13. mysql 怎么加上撇号_php - 如何在写入Mysql数据库时处理撇号
  14. html两行字的上下间隔,css字体上下间距怎么调?
  15. 快速排序--QuickSort()--递归版本
  16. 基于Linux中的通讯录管理系统(C语言+双向循环链表+MySQL)
  17. 软工实践第二次作业-黄紫仪
  18. 关于关联表用code还是id的见解
  19. [GoFrame学习] 报错 implement not found for interface IMenu, forgot register?
  20. Python ROS键盘控制机械臂

热门文章

  1. directx实现过程和原理
  2. GEM5是加载workload的(上)
  3. 使用squid代理时出现 The requested URL could not be retrieved
  4. 【修炼六】时间估算的三步曲
  5. 卡片游戏(队列的基础运用)
  6. 年终了,程序员这样谈加薪就稳了!
  7. QT添加应用程序的图标
  8. Android面试送分题:最新Android面试题整理,详细的Android学习指南
  9. Blender物体跟踪实战教程
  10. JS节点操作小结(创建节点,添加节点,获取节点,删除节点,复制节点)