React
-
介绍一下react
-
React单项数据流
-
react生命周期函数和react组件的生命周期
-
react和Vue的原理,区别,亮点,作用
-
reactJs的组件交流
-
有了解过react的虚拟DOM吗,虚拟DOM是怎么对比的呢
-
项目里用到了react,为什么要选择react,react有哪些好处
-
怎么获取真正的dom
-
选择react的原因
-
react的生命周期函数
-
setState之后的流程
-
react高阶组件知道吗?
-
React的jsx,函数式编程
-
react的组件是通过什么去判断是否刷新的
-
如何配置React-Router
-
路由的动态加载模块
-
Redux中间件是什么东西,接受几个参数
-
redux请求中间件如何处理并发
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
const obj = {count: 3}
const state1 = ref(obj.count)
const state2 = toRef(obj, ‘count’)
function add1() {
state1.value ++
console.log(‘原始值:’, obj);
console.log(‘响应式数据对象:’, state1);
}
function add2() {
state2.value ++
console.log(‘原始值:’, obj);
console.log(‘响应式数据对象:’, state2);
}
return {state1, state2, add1, add2}
}
}
我们分别用 ref
和 toRef
将 obj
中的 count
转化为响应式,并声明了两个方法分别使 count
值增加,每次增加后打印一下原始值 obj
和被包装过的响应式数据对象,同时还要看看视图的变化
ref:
可以看到,在对响应式数据的值进行 +1
操作后,视图改变了,原始值未改变,响应式数据对象的值也改变了,这说明 ref
是对原数据的一个拷贝,不会影响到原始值,同时响应式数据对象值改变后会同步更新视图
toRef:
可以看到,在对响应式数据的值进行 +1
操作后,视图未发生改变,原始值改变了,响应式数据对象的值也改变了,这说明 toRef
是对原数据的一个引用,会影响到原始值,但是响应式数据对象值改变后会不会更新视图
总结:
-
ref
是对传入数据的拷贝;toRef
是对传入数据的引用 -
ref
的值改变会更新视图;toRef
的值改变不会更新视图
了解完 toRef
后,就很好理解 toRefs
了,其作用就是将传入的对象里所有的属性的值都转化为响应式数据对象,该函数支持一个参数,即 obj
对象
我们来看一下它的基本使用
打印结果如下:
返回的是一个对象,对象里包含了每一个包装过后的响应式数据对象
听这个API的名称就知道,这是一个渐层的 reactive
,难道意思就是原本的 reactive
是深层的呗,没错,这是一个用于性能优化的API
其实将 obj
作为参数传递给 reactive
生成响应式数据对象时,若 obj
的层级不止一层,那么会将每一层都用 Proxy
包装一次,我们来验证一下
来看一下打印结果:
设想一下如果一个对象层级比较深,那么每一层都用 Proxy
包装后,对于性能是非常不友好的
接下来我们再来看看 shallowReactive
来看一下打印结果:
结果非常的明了了,只有第一层被 Proxy
处理了,也就是说只有修改第一层的值时,才会响应式更新,代码如下:
{{ state.a }}
{{ state.first.b }}
{{ state.first.second.c }}
<button @click=“change1”>改变1
<button @click=“change2”>改变2
来看一下具体过程:
首先我们点击了第二个按钮,改变了第二层的 b
和第三层的 c
,虽然值发生了改变,但是视图却没有进行更新;
当我们点击了第一个按钮,改变了第一层的 a
时,整个视图进行了更新;
由此可说明,shallowReactive
监听了第一层属性的值,一旦发生改变,则更新视图
这是一个浅层的 ref
,与 shallowReactive
一样是拿来做性能优化的
shallowReactive
是监听对象第一层的数据变化用于驱动视图更新,那么 shallowRef
则是监听 .value
的值的变化来更新视图的
我们来看一下具体代码
{{ state.a }}
{{ state.first.b }}
{{ state.first.second.c }}
<button @click=“change1”>改变1
<button @click=“change2”>改变2
首先看一下被 shallowRef
包装过后是怎样的结构
然后再来看看改变其值会有什么变化
我们先点击了第二个按钮,发现数据确实被改变了,但是视图并没随之更新;
于是点击了第一个按钮,即将整个 .value
重新赋值了,视图就立马更新了
这么一看,未免也太过麻烦了,改个数据还要重新赋值,不要担心,此时我们可以用到另一个API,叫做 triggerRef
,调用它就可以立马更新视图,其接收一个参数 state
,即需要更新的 ref
对象
我们来使用一下
{{ state.a }}
{{ state.first.b }}
{{ state.first.second.c }}
<button @click=“change”>改变
我们来看一下具体过程
可以看到,我们没有给 .value
重新赋值,只是在修改值后,调用了 triggerRef
就实现了视图的更新
toRaw
方法是用于获取 ref
或 reactive
对象的原始数据的
先来看一段代码
{{ state.name }}
{{ state.age }}
<button @click=“change”>改变
来看看具体过程
我们改变了 reactive
对象中的数据,于是看到原始数据 obj
和被 reactive
包装过的对象的值都发生了变化,由此我们可以看出,这两者是一个引用关系
那么此时我们就想了,那如果直接改变原始数据 obj
的值,会怎么样呢?答案是: reactive
的值也会跟着改变,但是视图不会更新
由此可见,当我们想修改数据,但不想让视图更新时,可以选择直接修改原始数据上的值,因此需要先获取到原始数据,我们可以使用 Vue3 提供的 toRaw
方法
toRaw
接收一个参数,即 ref
对象或 reactive
对象
上述代码就证明了 toRaw
方法从 reactive
对象中获取到的是原始数据,因此我们就可以很方便的通过修改原始数据的值而不更新视图来做一些性能优化了
注意: 补充一句,当
toRaw
方法接收的参数是ref
对象时,需要加上.value
才能获取到原始数据对象
markRaw
方法可以将原始数据标记为非响应式的,即使用 ref
或 reactive
将其包装,仍无法实现数据响应式,其接收一个参数,即原始数据,并返回被标记后的数据
我们来看一下代码
{{ state.name }}
{{ state.age }}
<button @click=“change”>改变
我们来看一下在被 markRaw
方法处理过后的数据是否还能被 reactive
包装成响应式数据
从图中可以看到,即使我们修改了值也不会更新视图了,即没有实现数据响应式
与 Vue2中的 provide
和 inject
作用相同,只不过在Vue3中需要手动从 vue
中导入
这里简单说明一下这两个方法的作用:
-
provide :向子组件以及子孙组件传递数据。接收两个参数,第一个参数是
key
,即数据的名称;第二个参数为value
,即数据的值 -
inject :接收父组件或祖先组件传递过来的数据。接收一个参数
key
,即父组件或祖先组件传递的数据名称
假设这有三个组件,分别是 A.vue
、B.vue
、C.vue
,其中 B.vue
是 A.vue
的子组件,C.vue
是 B.vue
的子组件
// A.vue
// B.vue
// C.vue
watch
和 watchEffect
都是用来监视某项数据变化从而执行指定的操作的,但用法上还是有所区别
watch:watch( source, cb, [options] )
参数说明:
-
source:可以是表达式或函数,用于指定监听的依赖对象
-
cb:依赖对象变化后执行的回调函数
-
options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)
当监听 ref
类型时:
当监听 reactive
类型时:
当同时监听多个值时:
因为 watch
方法的第一个参数我们已经指定了监听的对象,因此当组件初始化时,不会执行第二个参数中的回调函数,若我们想让其初始化时就先执行一遍,可以在第三个参数对象中设置 immediate: true
watch
方法默认是渐层的监听我们指定的数据,例如如果监听的数据有多层嵌套,深层的数据变化不会触发监听的回调,若我们想要其对深层数据也进行监听,可以在第三个参数对象中设置 deep: true
补充: watch方法会返回一个stop方法,若想要停止监听,便可直接执行该stop函数
接下来再来聊聊 watchEffect
,它与 watch
的区别主要有以下几点:
-
不需要手动传入依赖
-
每次初始化时会执行一次回调函数来自动获取依赖
-
无法获取到原值,只能得到变化后的值
来看一下该方法如何使用:
从上述代码中可以看出,我们并没有像 watch
方法一样先给其传入一个依赖,而是直接指定了一个回调函数
当组件初始化时,将该回调函数执行一次,自动获取到需要检测的数据是 state.count
和 state.name
根据以上特征,我们可以自行选择使用哪一个监听器
我们都知道在Vue2的任何一个组件中想要获取当前组件的实例可以通过 this
来得到,而在Vue3中我们大量的代码都在 setup
函数中运行,并且在该函数中 this
指向的是 undefined
,那么该如何获取到当前组件的实例呢?
这时可以用到另一个方法,即 getCurrentInstance
{{ num }}