上节课我们对react
的diffing
做了一些展开的讨论。接下来开始我们来进入react
脚手架的学习。但是我们一味地往前推进课程进度的话,大家会不会发现好像前面的一些基础知识都有所遗忘了?那么我们这节课先来对前面的一些react
基础来做一个大致的概括总结。
回顾
在开始复习react
基础知识之前呢,我们先来对上节课的内容来做一个简单的回顾。
diffing
算法会来对比新旧虚拟DOM
diffing
算法通过key
来比对新旧真实DOM
diffing
算法比对的最小单位是标签- 尽量使用数据唯一标识来做
key
以上便是我们上节课整体概括下来的知识要点。接下来我们开始复习react
前面的一些基础知识
简介
react
是一个将我们处理好的数据渲染成HTML
视图的这么样一个开源的JavaScript
库。通俗一点来说呢就是,你提供数据给react
,那么react
就帮你渲染成HTML
视图。
- 组件化模式,声明式编码,提高开发效率及组件复用率
react navtive
中可以使用react
语法进行移动端开发- 使用虚拟
DOM
+Diffing
算法,尽量减少与真实DOM
的交互 - 要求掌握的知识点:
- 判断
this
的指向 class
类ES6
语法npm
包管理器- 理解原型、原型链
- 数组常用方法
- 模块化
引入react
在前面的课程中,我们都是通过在html
文件中将react
本地文件来引入,从而实现引入react
库的目的。那么就需要注意一下几点:
react
库必须要在react-dom
之前引入- 引入
babel
库来支持jsx
语法 - 需要有容器来供
react
来渲染虚拟DOM
jsx
语法代码部分不能用引号把相关代码扩起来
创建虚拟DOM
我们说了react
中会使用虚拟DOM
从而尽量避免对真实DOM
的直接操作,那么如何创建虚拟DOM
- 直接使用
jsx
语法创建虚拟DOM
- 使用原生
js
语法来创建虚拟DOM
(不需要掌握,天塌下来也用不上) babel
库会自动把jsx
语法转换为原生js
语法创建虚拟DOM
,这样浏览器才能识别。jsx
创建虚拟DOM
的方法是原生js
语法创建虚拟DOM
的一个语法糖jsx
方法创建虚拟DOM
更加简洁明了,更加方便快捷
虚拟DOM
和真实DOM
当我们学会如何去创建和使用虚拟DOM
之后,其实我们还是一直挺疑惑,虚拟DOM
到底是什么呢?和真实DOM
又有什么区别呢?那么我们又对这两个家伙做了一次对比
- 虚拟
DOM
和真实DOM
本质上都是js
对象,但是console.log
打印真实DOM
呈现出的是element
- 虚拟
DOM
的属性数量或者API
数量要远远少于真实DOM
,所以虚拟DOM
更加轻量级 - 虚拟
DOM
只在react
内部使用,必须由react
映射成真实DOM
才呢个呈现在页面上 - 可以用
typeof
来获取某变量的类型 - 可以用
instanceof
来判断某变量是不是某类型
JSX
的语法规则
当我们对比了虚拟DOM
和真实DOM
之后,我们就要继续往下开始后面的课程了,都知道创建虚拟DOM
有两种方法,而最高效而且方便的就是JSX
,那么JSX
语法是什么样的呢?都有哪些规则呢?
jsx
是类似于XML
的js
扩展语法jsx
的本质是React.createElement(compoment,props,...children)
方法的语法糖。jsx
可以使用HTML
标签,但是jsx
表达式中的的标签不是HTML/XML
标签jsx
内需要通过{}
来对js
表达式进行支持。jsx
任何标签中class
属性的指定必须用className
来指定jsx
内联样式必须使用style={{key: value}}
的方式来写jsx
虚拟DOM
只允许有一个根标签。jsx
虚拟DOM
中的任何一个标签都必须闭合。jsx
中的标签在被渲染时会检查标签首字母- 如果
jsx
中标签首字母小写,那么则将该标签渲染为HTML
中同名标签,若无同名标签则会报错。 - 如果
jsx
中标签首字母大写,那么react
就去渲染对应的组件,若该组件没有定义,则报错。
- 如果
组件与模块
当我们了解了JSX
的语法规则之后,又做了一个小练习。但是我们渐渐的发现,好像当我们代码量或者功能点过多时好像也还挺麻烦的,于是react
中的另一个核心的东西出现了。就是组件。那么什么是组件,怎么用呢?
- 向外提供特定功能的
js
程序,一般就是一个js
文件叫做模块 - 用来实现局部功能效果的代码和资源集合(
HTML
,CSS
,JS
等等)叫做组件 - 当应用使用组件和模块进行编程,就叫组件化和模块化
- 组件分为函数式组件和类式组件
- 函数式组件的本质就是一个函数
- 类式组件本质就是一个类
- 定义组件首字母必须大写
- 定义函数式组件必须有返回值
- 渲染组件必须写成标签形式
复习类的相关知识
我们刚一引入组件这个概念的时候,按照惯例都是先学习简单的,所以就先介绍了函数式组件,但是实际上,类组件才是我们的重中之重,倒不是说函数式组件不重要,也重要,但是类组件更重要。那么工欲善其事,必先利其器。所以我们在学习类组件之前复习了一下原生js
中类的相关知识
- 类中的构造器并不是必须要写的
- 要对实例进行一些初始化的操作才需要写构造器
- 如果
A
继承了B
类,那么A
类的构造器方法必须在第一步就调用super
方法 - 类中定义的方法是放在了类的原型对象上供实例对象来使用。
- 类的实例对象在调用方法时会优先从自身原型对象上查找方法,如果没有找到则通过原型链去父类的原型对象中去查找
类组件
在我们终于复习完了关于类的相关知识之后,那么我们就要正式开始学习类组件了,那么类组件有是什么样子的呢?都有哪些规则呢?
- 要使用类组件就要定义类
- 类组件创建的类必须继承
React.Component
类 - 类组件创建的类里面必须要有一个
render
方法 render
方法一定要有返回值。render
方法存放在类的原型对象中react
在渲染类组件时会自动实例化类
组件的三大核心属性
我们其实在刚一接触到组件的时候就提到过组件有三大核心属性。那么这三大属性都是什么呢?各种都有什么用途和规则?
- 组件有简单组件和复杂组件之分
- 简单组件没有状态
- 复杂组件有状态
- 状态里面存储页面所需要的数据,数据更新则驱动页面展示
- 状态在类组件实例对象上
- 我们所说的组件的三大属性,实际上是组件实例的三大属性
state
属性- 如果通过
state
驱动页面需要借助构造器方法 - 构造器方法的参数官方规定的是
props
- 构造器方法要将
props
参数传给super
state
要传一个对象- 通过
this
来调用state
react
不支持直接修改state
,必须通过setState
方法来修改state
setState
存放在React.Component
的原型对象上setState
方法接收的参数是一个对象setState
方法并不是直接全局替换掉原来的state
而是合并- 整个过程中类组件的构造器方法只被调用一次
render
方法被调用1 + n
次- 标准写法比较繁琐,在实际开发中会拖慢我们的进度,所以要进行精简
- 精简后的代码结构分为三个部分,就目前来说,不需要构造器,至于后面要不要我们再说
- 赋值语句直接初始化状态
render
方法- 自定义方法,所有自定义方法全部使用赋值语句加箭头函数来写
- 箭头函数自身没有
this
- 箭头函数中如果要使用
this
,那么就会去查找箭头函数外层的this
并作为自己的this
来使用 props
属性props
是一个对象props
是通过外面往组件内传入数据props
在组件的实例对象上可以通过this
调用props
可以在组件标签处通过标签属性传入props
可以在标签中使用展开运算符展开一个对象来批量传入属性props
在使用展开运算符时必须确保被展开对象中的属性和解构props
时的变量一致才能正常取数- 展开运算符在原生
js
语法中不能展开对象 babel
和react
库支持仅在组件标签批量传入属性时展开对象- 对
props
限制并不是必须的 - 限制
props
必须引入prop-types
- 限制可以避免一些不必要的错误
- 限制有三种场景
- 限制属性是否必须非空
- 限制属性类型
- 限制属性默认值
- 限制属性类型为函数时,不能用
function
而要用func
propsTypes
和defaultProps
必须是组件类自身的属性,不是实例对象的属性- 用
static
关键字给类自身添加属性 props
是只读的- 类组件不写构造器完全可以,而且能不写就尽量不写
- 构造器中
props
传给super
和不传给super
的区别就是在构造器中能否通过this
访问到props
- 函数式组件目前只能使用
props
- 函数式组件使用参数来接收
props
- 函数式组件可以限制
props
但是只能写在函数体外 refs
属性refs
是一个收集各个标签ref
属性来作为标识的一个对象refs
可以代替document.getElementById
方法来获取页面节点refs
可以配合事件处理来完成相应的功能需求。- 回调式
refs
不会自动收集到this.refs
中 - 字符串式
refs
有问题,后期可能会废弃 - 回调式
refs
所传入的ref
属性是一个回调函数 - 回调式
refs
是将传入的标签节点传入回调函数,并通过回调函数将标签节点挂在实例自身 - 回调式
refs
会在页面第一次被渲染时调用一次 - 如果回调式
refs
是内联函数形式,那么在state
更新之后,会被重新调用两次 - 内联函数形式的回调式
refs
调用次数对程序不会有影响 - 类组件绑定函数的方式可以解决
refs
被多次调用的问题 createRef
可以返回一个容器用于存放被ref
属性标识的DOM
节点createRef
返回的容器“专人专用”- 如果多个标签要被标识,就要创建多个容器
react
事件绑定与事件处理
在我们学习三大属性时不知道大家还记不记得,我们的点击事件中出了一些问题。到了后来我们学完三大属性之后又对事件处理做了一些介绍。
- 原生
js
添加点击事件有三种方法 addEventListener
方法onclick
方法onclick
属性配合回调函数react
中允许使用原生js
中的方法react
不推荐使用addEventListener
和onclick
,大力推崇onClick
属性配合回调函数react
中onClick
属性中click
首字母必须大写onClick
属性不能用引号括起来,需要用{}
括起来onClick
属性必须是函数,所以函数名后面不可以加()
react
类组件中推荐将类组件需要用到的函数全部包含在类里,以方法的形式来写- 类组件中的方法要通过
this
调用 - 类方法赋值给变量或者作为事件监听的回调的话,对该方法的调用属于函数直接调用而不是通过类的实例对象调用
- 类中所有方法都默认局部开启了
strict
模式 bind(this)
做了两件事- 生成新函数
- 修改新函数中的
this
指向 - 实例对象调用属性和方法会先从自身查找,自身没有才会顺着原型链去查找原型对象
this.notify = this.notify.bind(this)
是将原型对象上的notify
方法生成新函数并修改this
指向之后存放在实例对象自身- 不要过度使用
ref
- 事件监听要严格注意大小写
- 通过
event.target
获取到事件发生的DOM
元素
受控组件与非受控组件
随着我们学习的东西越来越多,我们所接触到的需求也就会越来越复杂。那么我们就遇到一些需求需要使用受控组件来完成,那么有受控组件自然也就会有非受控组件。那么这俩又分别是什么东西呢?
我们通过一个表单的案例得出了结论: 现用现取则是非受控,而在输入过程中就取值并维护到state
中的就是受控。
高阶函数
我们在学习完受控和非受控组件之后我们又通过案例学习了关于高阶函数的使用
- 高阶函数有两个评判标准,满足其中一个就可以
- A 函数接收的参数是一个函数
- A 函数的返回值是一个函数
- 通过函数调用继续返回函数的方式实现多次接收函数最后统一处理的函数形式叫做函数的柯里化。
引出生命周期
当然前面几节或许有人在觉得这仿佛是题外话,那么我们就来说说不是题外话的东西。生命周期。我们通过一个案例来引出了生命周期的一个简约的轮廓。
- 组件渲染就是组件挂载,清空组件就是组件卸载
- 组件在挂载完成之后会自动调用
componentDidMount
方法 - 组件在卸载之前会自动调用
componentWillUnmount
旧版生命周期
- 单一组件挂载到卸载整个生命周期中有 5 个生命周期钩子被按顺序调用
constructor
构造器方法- 在组件即将挂载之前调用
componentWillMount
方法 - 调用
render
方法来挂载组件 - 完成组件挂载后立即调用
componentDidMount
- 即将卸载前调用
componentWillUnmount
方法 - 组件中各个生命周期钩子的定义顺序对程序执行没有影响,生命周期钩子执行的顺序依赖与生命周期的流程
- 组件完成挂载并执行完了
componentDidMount
之后按顺序执行了 4 个生命周期钩子 - 通过
shouldComponentUpdate
方法判断是否允许更新 - 通过
componentWillUpdate
方法做更新前的准备工作 - 通过
render
方法更新组件 - 更新组件之后立即调用
componentDidUpdate
方法 shouldComponentUpdate
必须返回bool
类型- 如果没有写
shouldComponentUpdate
方法,react
会自动补齐该方法,并且默认该方法返回true
forceUpdate
比setState
少一个shouldComponentUpdate
环节forceUpdate
与setState
的本质区别就是forceUpdate
不对state
做任何更改forceUpdate
不受shouldComponentUpdate
方法的限制- 只有当父组件的
render
方法被重新调用才会触发更新流程 - 只有当父组件的
render
方法被重新调用才会触发componentWillReceiveProps
的调用 - 当父组件被重新调用的时候,子组件不会被重新挂载
componentWillReceiveProps
方法在子组件接收到props
之前调用
新旧生命周期的对比
在深入学习新版生命周期之前,我们把新旧生命周期在一起对比着介绍了一下。
- 新版本生命周期可以使用旧版本的钩子
- 新版本中废弃了三个旧版本中的钩子,使用这三个钩子要加
UNSAFE
前缀 componentWillMount
componentWillUpdate
componentWillReceiveProps
- 新版本中新增了两个钩子
getDerivedStateFromProps
getSnapshotBeforeUpdate
新版生命周期
那么既然做了对比,新版生命周期中的变化是什么样子的呢
- 仅当
state
值在任何时候都完全取决于props
是才使用getDerivedStateFromProps
钩子 - 派生
state
会导致代码冗余且组件难以维护 - 使用了派生
state
之后,将无法再正常通过state
驱动页面更新 getSnapshotBeforeUpdate
钩子在render
和componentDidUpdate
getSnapshotBeforeUpdate
钩子必须要有返回值,可以为不是undefined
的任何值getSnapshotBeforeUpdate
钩子的返回值会顺流传给componentDidUpdate
componentDidUpdate
会接收组件更新前的snapshot
,props
和state
Diffing
算法
其实以上的这些内容就已经算是学完了react
的基础知识了,但是我们还是对开篇所说的diffing
算法有点好奇,那么我们就展开讨论了一些关于diffing
算法的内容。
diffing
算法会来对比新旧虚拟DOM
diffing
算法通过key
来比对新旧真实DOM
- 尽量使用数据唯一标识来做
key
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/review_react_basic/