vue3其他Composition api
shallowReactive 与 shallowRef
- shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)
- shallowRef: 只处理了 value 的响应式, 不进行对象的 reactive 处理
什么时候用浅响应式呢?
- 一般情况下使用 ref 和 reactive 即可
- 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
- 如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51<template>
<h2>shallowReactive 与 shallowRef</h2>
<h3>m1:{{ m1 }}</h3>
<h3>m2:{{ m2 }}</h3>
<h3>m3:{{ m3 }}</h3>
<h3>m4:{{ m4 }}</h3>
<hr />
<button @click="handleUpdata">更新数据</button>
</template>
<script lang="ts">
import {
defineComponent,
reactive,
ref,
shallowReactive,
shallowRef,
} from "vue";
export default defineComponent({
name: "",
setup() {
// m1 reactive 深度劫持,深度响应式
const m1 = reactive({ a: 1, b: { c: 2 } })
const m2 = shallowReactive({ a: 1, b: { c: 2 } })
const m3 = ref({ a: 1, b: { c: 2 } })
const m4 = shallowRef({ x: 1, y: { c: '2' } })
const handleUpdata = () => {
// m1.b.c += 1
// m2.b.c += 1
// m3.value.a += 1
// m3.value.b.c += 1
// m4.value.y.c += 1
console.log(m3);
console.log(m4);
// 为什么reactive或ref在使用时,shallowRef和shallowReactive的数据会变成响应式?
// 数据处于同一环境,都被同一个Fragment包着,Fragment是一种VNode的类型,m1.b.c触发改变
// 对应的模板领域会进行更新,所以会发生改变
}
return {
m1,
m2,
m3,
m4,
handleUpdata,
};
},
});
</script>
readonly 与 shallowReadonly
- readonly 深度只读数据 shallowReadonly: 浅只读数据
应用场景:
在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39<template>
<h2>readonly 与 shallowReadonly</h2>
<h3>state:{{ state2 }}</h3>
<hr />
<button @click="handleUpdata">更新数据</button>
</template>
<script lang="ts">
import { defineComponent, reactive, readonly, ref, shallowReadonly } from "vue";
export default defineComponent({
name: "",
setup(props, { attrs, emit, slots }) {
const state = reactive({
name:'he',
age:20,
car:{
name:'红旗'
}
})
// 只读数据---深度只读 对象的属性不能修改,对象的对象的属性也不能修改
// const state2 = readonly(state)
// 只读数据---浅度只读 对象的属性不能修改,对象的对象的属性可以修改
const state2 = JSON.parse(JSON.stringify(shallowReadonly(state)))
// 问题:state对象里的属性改变,也会影响state2对象里的属性(浅拷贝)
// 解决:JSON.parse(JSON.stringify(shallowReadonly(state))) 进行深拷贝
const handleUpdata = ()=>{
// state2.name += '=='
state2.car.name += '--'
console.log(state.car,state2.car);
}
return {
state2,
state,
handleUpdata
};
},
});
</script>
toRaw 与 markRaw
- toRaw:把代理对象变成普通对象,数据变化,界面不变化
- toRaw:返回由 reactive 或 readonly 方法转换成响应式代理的普通对象
- markRaw:markRaw标记的对象,不能成为代理对象,数据不能在页面更新
markRaw应用场景:
有些值不应被设置为响应式的,例如复杂的第三方类实例或 Vue 组件对象。
当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。
1 | <template> |
toRef
- 为源响应式对象上的某个属性创建一个 ref 对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
const age = toRef(state, "age")
- 区别ref : 拷贝了一份新的数据值单独操作, 更新时相互不影响
- 应用: 当要将 某个 prop 的 ref 传递给复合函数时,toRef 很有用
App.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45<template>
<h2>toRef</h2>
<h3>state:{{ state }}</h3>
<h3>age:{{ age }}</h3>
<h3>name:{{ name }}</h3>
<hr />
<button @click="handleUpdata">toRaw</button>
<Child :age='age'></Child>
</template>
<script lang="ts">
import { defineComponent, reactive, toRef, ref } from "vue";
import Child from './components/Child.vue'
export default defineComponent({
name: "",
components:{
Child
},
setup() {
const state = reactive({
name: "he",
age: 20,
car: {
name: "红旗",
},
});
// 把响应式数据state的属性age变成ref对象
const age = toRef(state, "age");
// 把响应式数据state的属性name,使用ref进行包装,变成ref对象
const name = ref(state.name);
console.log(age,name);
const handleUpdata = () => {
state.age += 2
// name.value += 3
};
return {
state,
age,
name,
handleUpdata,
};
},
});
</script>Child.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34<template>
<h2>Child组件,子组件</h2>
<h3>age:{{ age }}</h3>
<h3>length:{{ length }}</h3>
</template>
<script lang="ts">
import { computed, defineComponent, Ref, ref, toRef } from "vue";
// 参数必须是一个Ref类型的数据
function useGetLength(age:Ref) {
return computed(() => {
return age.value.toString().length;
});
}
export default defineComponent({
name: "",
// props: {
// age: {
// type: Number,
// required: true,
// },
// },
props: ["age"],
setup(props, { attrs, emit, slots }) {
//把一个对象里的属性,变成ref对象
const length = useGetLength(toRef(props, "age"));
console.log(length);
console.log(props);
return {
length,
};
},
});
</script>
customRef
- 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
需求: 使用 customRef 实现 debounce 的示例
get: 告诉vue追踪数据:track() set: 告诉Vue更新页面:trigger()
1 | <template> |
provide 与 inject:父组件与孙子组件之间的通信
provide和inject提供依赖注入,功能类似 2.x 的provide/inject
实现跨层级组件(祖孙)间通信
App.vue(父组件)
1 | <template> |
Child.vue(子组件)
1 | <template> |
Grandson.vue(孙组件)
1 | <template> |
响应式数据的判断
isRef: 检查一个值是否为一个 ref 对象
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
1 | <template> |