Vue Ref、reactive、toRefs、toRef、customRef 创建响应式数据
Ref
js
import { ref } from 'vue';
setup(){
const a = ref(0); // 一般用于定义基本类型响应式, 返回 Ref 对象
function add(){
a.value ++; // js 中操作数据: xxx.value,模板中则不需要
}
return{
a,add
}
}
reactive
js
let num = ref(0);
let obj = reactive({}) // 用于创建引用类型响应式
let obj = reactive({num}) // ref 会被解包 obj.num === num.value
obj.num = num // ref 赋值给 reactive 属性也会被解包,obj.num === num.value
响应式原理
js
let obj = {
name: 'name',
arr: []
}
- target 被代理的对象
- handler 处理器对象,监视数据操作
js
let pro = new Proxy(obj,{
get(target,prop){
console.log('get方法');
return Reflect.get(target,prop); // 读取对象的值
},
set(target,prop,value){
console.log('set方法调用');
return Reflect.set(target,prop,value); // 设置对象的值
},
deleteProperty(target,prop){
console.log('delete方法调用了');
return Reflect.deleteProperty(target,prop ); // 设置对象的值
}
})
toRefs
js
const reactiveObj = reactive({
num: 1,
})
// 将 reactive 对象转成 ref 对象,可用于解构
const toRefObj = toRefs(reactiveObj);
setInterval(() => {
// reactiveObj.num ++ ;
toRefObj.num.value++
},1000)
return {
reactiveObj,
...toRefObj,
}
toRef
js
const user = reactive({
age: 18,
money: 20,
});
// toRef age 与 user 互通
const age = toRef(user, "age");
// ref money 与 user 不互通
const money = ref(user.money);
组件中的应用
html
<!-- 这里传入的是 age.value -->
<child :age='age'/>
<!-- child组件 -->
<template>
<div>{{ age }}</div>
<div>{{ length }}</div>
</template>
js
// 别人写的 hook 函数
const getLength = (age: Ref) => computed(() => age.value.toString().length);
export default defineComponent({
name: "child",
props: {
age: {
type: number,
required: true,
},
},
setup(props) {
// 传入 props 把 age 变为 ref 对象并且同步响应
const length = getLength(toRef(props, "age"));
return { length };
},
});
customRef
创建自定义的响应式
html
<input v-model="text" />
<div>{{text}}</div>
js
import {customRef} from 'vue'
const useDebouncedRef = (value, delay = 200) => {
let timeout
return customRef((track, trigger) => {
get() {
track() // 跟踪 return 出去的 value
return value
},
set(newValue) {
// 延迟后设置新的值
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger() // 通知 vue 触发模板更新
}, delay)
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello')
}
}
}