React知识点(一):juejin.cn/post/690022…
了解JSX的本质
1. JSX和Reat.createElement和Babel
我们除了学习JSX的用法和特性,对JSX本质进行一些了解,对写JSX是有非常大的帮助的,可以让我们写出效率更高的代码,接下来让我们一起来了解窥探JSX的本质:
实际上JSX只是React.createElement(type,config,...children)函数的语法糖。也就是说我们写的JSX其实最终都会转化成React.createElement函数的形式再渲染到render函数上。而我们的babel就是提供了JSX的语法糖。所以我们在使用JSX的时候必须使用babel。
JSX -> Babel -> React.creatElement
2. React.createElement的参数
@param1:type
当前ReactElement的类型
如果是标签元素,那么就使用字符串表示"div"
如果是组件元素,那么直接使用组件的名称
@param2:config
创建element元素的属性,config是一个对象
@params3:children
存放标签的内容,以
虚拟Dom的创建过程
我们通过React.createElement最终的目的是创建一个ReactElement对象。该对象是一个JavaScript的对象树。我们称为虚拟DOM。而这个虚拟DOM最终会通过ReactDOM.render()函数渲染到真实的DOM树上。
所以JSX语法中写的标签会经历这样一个过程:
JSX(语法糖) -> React.creatElement(函数) -> ReactElement(对象树) -> ReactDOM.render -> 真实DOM树
为什么采用虚拟DOM的形式而不直接修改真实的DOM呢?
-
操作真实DOM很难跟踪发生的改变:原有的开发模式,对真实DOM操作很难跟踪到状态的改变,不方便针对我们应用程序进行调试。
-
操作真实的DOM性能较低。
- 因为真实的DOM是一个非常复杂的对象,不同虚拟DOM,可能虚拟DOM对象的属性涵盖只有几个属性。我们可以尝试打印一下浏览器中真实的DOM。比较法相真实的DOM比虚拟DOM要复杂太多太多了。所以说操作真实DOM性能很低。
- DOM操作会引起浏览器的回流和重绘
1. React官方对于虚拟DOM的说法:
虚拟DOM是一种编程理念。在这个理念中,UI以一种理想化或者说虚拟化的方式保存在函数中,并且它是一个相对简单的JavaScript对象。我们可以通过ReactDOM.render函数让虚拟DOM和真实DOM同步起来,这个过程叫做协调。
React的更新机制
我们来说一下React中diffing算法。如果一颗树要参考另外一颗树进行完全更新,那么即使使用现在最先进的方法,该算法的复杂度也为O(n3),是个极为复杂的算法。需要耗费大量的资源。
这样做是肯定不能满足我们快速更新页面的,那么React是怎么做的呢?原来React对比较算法进行了对比阉割的优化,什么意思呢?
- React在对比的时候,只会对同层节点进行比较。不同层的节点是不会进行比较的
- 在发现一个类型节点不一样的时候,会直接替换该节点及节点下的所有树
- 当对比两个元素类型相同,属性不一样。React会保留Dom节点,只更新Dom节点的属性
- 通过key来指定哪些节点在不同渲染情况下的稳定(优化子节点比较)
通过上述对diffing算法的改进,大大提升了重新渲染dom的效率。
key的注意事项
- key应该上述唯一的
- key不要使用随机数
- 使用index作为key,对性能是没有优化的
render函数被调用
当更新父组件时候,我们知道这时候的render函数会重新执行和渲染,但我们只更新的是父组件的内容,而子组件并没有实际的更新,但是render函数默认会把子组件也随父组件一起重新执行渲染。
这样就导致多了很多不必要的渲染,我们优化这种情况呢?
使用shouldComponentUpdate生命周期函数,该声明周期函数返回false的时候表示更新后不重新渲染组件。
//..
shouldComponentUpdate(nextProps,nextState) {
//比较某个state是否发生变化,如果发生变化返回true,即重新渲染组件
if(this.state.counter !== nextState.counter) { return true }
//默认不重新渲染页面
return false
}
上述生命周期虽然可以实现。但当有多个状态需要设置的时候,这个代码写起来太麻烦了。另一个解决方式是组件类继承PureComponent
函数式组件memo的使用
//导入
import React,{ PureComponent, memo } from "react";
//memo中传入一个函数组件,生成一个新的函数组件,该组件实现了监听状态改变时是否要执行render函数
const memoHeader = memo(fnHeader)