时间:2021-05-25
在开发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(<h1 onClick = {this.handleClick}> {this.state.Number} </h1>) }}从控制台的打印结果可以看出:共打印了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如果调用层次比较深
Number 是一个数字变量
NumberObject是一个对象
数字变量(number类型)和对象(Object)类型的内存存储机制不同
这时候,因为两者都指向堆中的同一个对象,所以一直都是true shouldComponentUpdate失效了
js变量分为基本类型的变量和引用类型的变量
对于number,string,boolean,undefined,null这些基本类型变量,值存在栈中
对于object,Array,function这些引用类型变量,引用存在栈中,而不同的引用却可以指向堆内存中的同一个对象
那么,问题就来了
怎么样才能取到不同的NumberObject呢?
四种方法:
1、ES6的扩展语法Object.assign()
2、深拷贝/浅拷贝或利用JSON.parse(JSON.stringify(data))相当于深拷贝,但使用受一定限制
3、引入immutable.js react官方推荐的第三方库
4、继承react的PureComponent组件(代替Component)
在js中,引用类型的数据,优点在于频繁的操作数据都是在原对象的基础上修改,不会创建新对象,从而可以有效的利用内存,不会浪费内存,这种特性称为mutable(可变),但恰恰它的优点也是它的缺点,太过于灵活多变在复杂数据的场景下也造成了它的不可控性,假设一个对象在多处用到,在某一处不小心修改了数据,其他地方很难预见到数据是如何改变的,针对这种问题的解决方法,一般就像刚才的例子,会想复制一个新对象,再在新对象上做修改,这无疑会造成更多的性能问题以及内存浪费。
为了解决这种问题,出现了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 --> Listimmutable.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组合 返回的是新数据,而不是数据的长度
优点:
缺点:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
在React中,条件渲染可以通过多种方式,不同的使用方式场景取决于不同的上下文。在本文中,我们将讨论所有可用于为React中的条件渲染编写更好的代码的方法。条件
React避免重复渲染React在渲染出的UI内部建立和维护了一个内层的实现方式,它包括了从组件返回的React元素。这种实现方式使得React避免了一些不必要
详解React16中的异常处理异常处理在React15.x及之前的版本中,组件内的异常有可能会影响到React的内部状态,进而导致下一轮渲染时出现未知错误。这些
学习react也有一段时间了,使用react后首页渲染的速度与seo一直不理想。打算研究一下react神奇服务端渲染。react服务端渲染只能使用nodejs做
前言本文主要给大家介绍了关于React列表渲染的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。示例详解:列表渲染也很简单,利用map