vue3学习—ReactivityAPI
vue3学习—ReactivityAPI
- 一、ReactivityAPI
- 1、获取响应式数据
- 1.reactive
- 2.readonly
- 3.ref
- 4.computed
- 5.获取响应式数据
- 3、监听数据变化
- 1.watchEffect
- 2.watch
- 3、判断
- 4、转换
- 1.unref
- 2.toRef
- 3.toRefs
一、ReactivityAPI
前面我们已经在使用的setup函数、onMounted、onUmMounted等生命周期钩子函数,都是属于composition api。
而ref、computed是属于Reactivity API的,这里我们开始介绍什么是Reactivity API。
1、获取响应式数据
1.reactive
代理一个对象(可深度代理)
import { reactive } from "vue"
const state = reactive({a: 1,b: 2});
window.state = state;

2.readonly
只能读取代理对象中的成员。
import { reactive, readonly } from "vue"
const isState = readonly({c: 2});
window.isState = isState;
如果给只读的代理成员赋值,会警告。

readonly也可以代理一个代理对象。
import { reactive, readonly } from "vue"
const state = reactive({a: 1,b: 2});
window.state = state;
const isState = readonly(state);
window.isState = isState;
尽管是代理的一个代理对象,两者之间也不会相等,但是引用值的关系存在,改变一者,两者皆改。

3.ref
前面两者是代理对象的使之成为响应式数据,那么还需要方法对原始值进行代理。
import { reactive, readonly, ref } from "vue"
const valRef = ref(0);
window.valRef = valRef;

如果你仍然用ref试图去代理一个对象,也可以。
import { reactive, readonly, ref } from "vue"
const valRef = ref({d: 5});
window.valRef = valRef;
如果给ref的值是一个对象,实际会通过reactive函数进行代理

如果给ref的就是一个代理值。
import { reactive, readonly, ref } from "vue"
const state = reactive({a: 1,b: 2});
window.state = state;
const valRef = ref(state);
window.valRef = valRef;
会直接直接使用代理。

4.computed
import { computed, reactive, readonly, ref } from "vue"
const state = reactive({a: 1,b: 2});
const sum = computed(()=>{console.log('computed');return state.a + state.b;
})
console.log(sum.value);
console.log(sum.value);
console.log(sum.value);
console.log(sum.value);
没有缓存时执行,有缓存时直接拿取。

5.获取响应式数据
| API | 传入 | 返回 | 备注 |
|---|---|---|---|
reactive | plain-object | 对象代理 | 深度代理对象中的所有成员 |
readonly | plain-object or proxy | 对象代理 | 只能读取代理对象中的成员,不可修改 |
ref | any | { value: ... } | 对value的访问是响应式的 如果给value的值是一个对象, 则会通过 reactive函数进行代理如果已经是代理,则直接使用代理 |
computed | function | { value: ... } | 当读取value值时, 会根据情况决定是否要运行函数 |
应用:
- 如果想要让一个对象变为响应式数据,可以使用
reactive或ref - 如果想要让一个对象的所有属性只读,使用
readonly - 如果想要让一个非对象数据变为响应式数据,使用
ref - 如果想要根据已知的响应式数据得到一个新的响应式数据,使用
computed
看一道题,以下代码输出什么:
import { reactive, readonly, ref, computed } from "vue";const state = reactive({firstName: "Xu Ming",lastName: "Deng",
});
const fullName = computed(() => {console.log("changed");return `${state.lastName}, ${state.firstName}`;
});
console.log("state ready");
console.log("fullname is", fullName.value);
console.log("fullname is", fullName.value);
const imState = readonly(state);
console.log(imState === state);const stateRef = ref(state);
console.log(stateRef.value === state);state.firstName = "Cheng";
state.lastName = "Ji";console.log(imState.firstName, imState.lastName);
console.log("fullname is", fullName.value);
console.log("fullname is", fullName.value);const imState2 = readonly(stateRef);
console.log(imState2.value === stateRef.value);
- state ready
- changed(computed没有缓存,运行函数)
- fullname is Deng,Xu Ming
- fullname is Deng,Xu Ming
- false
- true(state已经是一个代理,ref直接使用)
- Cheng Ji
- changed(computed依赖变了)
- fullname is Ji,Cheng
- fullname is Ji,Cheng
- false(一个state,一个只读,肯定false)
按照下面的要求完成函数:
function useUser(){// 在这里补全函数return {user, // 这是一个只读的用户对象,响应式数据,默认为一个空对象setUserName, // 这是一个函数,传入用户姓名,用于修改用户的名称setUserAge, // 这是一个函数,传入用户年龄,用户修改用户的年龄}
}
import { reactive, readonly } from "vue"
function useUser(){const userRef = reactive({});const user = readonly(userRef);const setUserName = (name) =>{userRef.name = name;}const setUserAge = (age) =>{userRef.age = age;}return {user,setUserName,setUserAge}
}
3、监听数据变化
1.watchEffect
监听依赖的变化,并且会立即执行。
import { reactive, ref, watchEffect } from "vue"
const state = reactive({a: 1,b: 2});
const count = ref(0);
watchEffect(()=>{console.log(state.a, count.value);
});

import { computed, reactive, readonly, ref, watchEffect } from "vue"
const state = reactive({a: 1,b: 2});
const count = ref(0);
watchEffect(()=>{console.log(state.a, count.value);
});
state.a++;
state.a++;
state.a++;
count.value++;
count.value++;
如果依赖多次变化,该任务回调为异步微任务,只会输出最终结果。

2.watch
监听单个数据的变化
import { reactive, watch } from "vue"
const state = reactive({a: 1,b: 2});
// 监听单个数据的变化
watch(state.a, (newValue, oldValue) => {console.log('watch',newValue, oldValue);
});
state.a++;
console.log('state',state.a);
这里我们想监听state.a的变化,发现出发了警告。
因为这里的state.a已经是一个常量1了,1是不会有变化的。

import { reactive, watch } from "vue"
const state = reactive({a: 1,b: 2});
// 监听单个数据的变化
watch(()=>state.a, (newValue, oldValue) => {console.log('watch',newValue, oldValue);
},{immediate: true//该属性让回调函数立即执行
});
state.a++;
console.log('state',state.a);
我们需要将state.a变成依赖即可,当然如果直接监听一个ref(x).value一样会警告,但是监听ref(x)可以。
const countRef = ref(0);
watch(countRef, (newValue, oldValue) => {// ...
})

监听多个数据的变化
// 监听多个数据的变化
watch([() => state.count, countRef], ([new1, new2], [old1, old2]) => {// ...
});
经历上面的监听数据变化的API,看如下提
import { reactive, watchEffect, watch } from "vue";
const state = reactive({count: 0,
});
watchEffect(() => {console.log("watchEffect", state.count);
});
watch(() => state.count,(count, oldCount) => {console.log("watch", count, oldCount);}
);
console.log("start");
setTimeout(() => {console.log("time out");state.count++;state.count++;
});
state.count++;
state.count++;console.log("end");
- watchEffect 0(watchEffect立即执行)
- start(同步)
- end(同步)
- watchEffect 2(微队列)
- watch 2 0(微队列)
- time out(宏队列)
- watchEffect 4
- watch 4 2
3、判断
| API | 含义 |
|---|---|
isProxy | 判断某个数据是否是由reactive或readonly |
isReactive | 判断某个数据是否是通过reactive创建的详细:https://v3.vuejs.org/api/basic-reactivity.html#isreactive |
isReadonly | 判断某个数据是否是通过readonly创建的 |
isRef | 判断某个数据是否是一个ref对象 |
4、转换
1.unref
等同于:isRef(val) ? val.value : val
应用:
function useNewTodo(todos){todos = unref(todos);// ...
}
2.toRef
得到一个响应式对象某个属性的ref格式
const state = reactive({foo: 1,bar: 2
})const fooRef = toRef(state, 'foo'); // fooRef: {value: ...}fooRef.value++
console.log(state.foo) // 2state.foo++
console.log(fooRef.value) // 3
3.toRefs
把一个响应式对象的所有属性转换为ref格式,然后包装到一个plain-object中返回
const state = reactive({foo: 1,bar: 2
})const stateAsRefs = toRefs(state)
/*
stateAsRefs: not a proxy
{foo: { value: ... },bar: { value: ... }
}
*/
应用:
setup(){const state1 = reactive({a:1, b:2});const state2 = reactive({c:3, d:4});return {...state1, // lost reactivity不在是响应式了...state2 // lost reactivity}
}setup(){const state1 = reactive({a:1, b:2});const state2 = reactive({c:3, d:4});return {...toRefs(state1), // reactivity...toRefs(state2) // reactivity}
}
// composition function
function usePos(){const pos = reactive({x:0, y:0});return pos;
}setup(){const {x, y} = usePos(); // lost reactivityconst {x, y} = toRefs(usePos()); // reactivity
}
博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
