为什么需要用 ref、toRef 和 toRefs
深入理解 ref、toRef 和 toRefs
为何需要 ref ?
- 返回值类型,会丢失响应式
- 如在 setup、computed、合成函数,都有可能返回值类型
- Vue 如不定义 ref,用户将自造 ref,反而混乱
例子
js
<template>
<p> why ref demo {{ age }}</p>
</template>
<script>
import {reactive, ref, toRefs} from "vue";
function useFeatureX() {
const state = reactive({
x: 1,
y: 2
})
return toRefs(state)
}
export default {
name: "WhyRef",
setup() {
// vue3 是通过 proxy 实现响应式,所以值类型不具备响应式
const {x, y} = useFeatureX()
let age = ref(20)
console.log(age)
// RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: 20, _value: 20}
// dep: Set(1) {ReactiveEffect}
// __v_isRef: true
// _rawValue: 20
// _shallow: false
// _value: 20
// value: 30
setTimeout(() => {
age.value = 30
}, 1500)
return {
age
}
}
}
</script>
为何需要 .value ?
- ref 是一个对象(不丢失响应式),value 存储值
- 通过 .value 属性的 get 和 set 实现响应式
- 用于模板、reactive 时,不需要 .value,其他情况都需要
例子
js
<template>
<p> why .value demo {{ state.age }} - {{ age1 }}</p>
</template>
<script>
import {computed, reactive, ref, toRefs} from "vue";
function useFeatureX() {
const state = reactive({
x: 1,
y: 2
})
return toRefs(state)
}
export default {
name: "WhyValue",
setup() {
// vue3 是通过 proxy 实现响应式,所以值类型不具备响应式
const {x, y} = useFeatureX()
const state = reactive({
name: 'lzw.',
age: 20
})
// computed 返回类似 ref 的对象,也有 .value
const age1 = computed(() => {
return state.age + 1
})
console.log(age1)
// ComputedRefImpl {dep: undefined, _dirty: true, __v_isRef: true, effect: ReactiveEffect, _setter: ƒ, …}
// dep: Set(1) {ReactiveEffect}
// effect: ReactiveEffect {active: true, deps: Array(1), fn: ƒ, scheduler: ƒ}
// __v_isReadonly: true
// __v_isRef: true
// _dirty: false
// _setter: () => {…}
// _value: 36
// value: 36
setTimeout(() => {
state.age = 35
}, 1500)
return {
state,
age1
}
}
}
</script>
通过模拟 computed,为啥需要 .value
js
// 模拟 computed,为啥需要 .value
function computed1(getter) {
let value;
setTimeout(() => {
value = getter();
}, 1000);
return value;
}
const a1 = computed1(() => 100);
console.log(a1); // undefined
function computed2(getter) {
const ref = {
value: null,
};
setTimeout(() => {
ref.value = getter();
}, 1000);
return ref;
}
const a2 = computed2(() => 100);
console.log(a2); // {value: null}value: 100[[Prototype]]: Object
为何需要 toRef 和 toRefs
- 初衷:不丢失响应式的情况下,把对象数据 分解/扩散/解构
- 前提:针对的是响应式对象(reactive封装的)非普通对象
- 注意:不创造响应式,而是延续响应式
例子
js
// 定义函数
function useFeatureX() {
const state = reactive({
x: 1,
y: 2,
});
// 返回时转为 ref
return toRefs(state);
}
export default {
setup() {
// 可以在不失去响应性的情况下破坏结构
const { x, y } = useFeatureX();
return { x, y };
},
};