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传入返回备注
reactiveplain-object对象代理深度代理对象中的所有成员
readonlyplain-object or proxy对象代理只能读取代理对象中的成员,不可修改
refany{ value: ... }对value的访问是响应式的
如果给value的值是一个对象,
则会通过reactive函数进行代理
如果已经是代理,则直接使用代理
computedfunction{ value: ... }当读取value值时,
根据情况决定是否要运行函数

应用:

  • 如果想要让一个对象变为响应式数据,可以使用reactiveref
  • 如果想要让一个对象的所有属性只读,使用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);
  1. state ready
  2. changed(computed没有缓存,运行函数)
  3. fullname is Deng,Xu Ming
  4. fullname is Deng,Xu Ming
  5. false
  6. true(state已经是一个代理,ref直接使用)
  7. Cheng Ji
  8. changed(computed依赖变了)
  9. fullname is Ji,Cheng
  10. fullname is Ji,Cheng
  11. 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");
  1. watchEffect 0(watchEffect立即执行)
  2. start(同步)
  3. end(同步)
  4. watchEffect 2(微队列)
  5. watch 2 0(微队列)
  6. time out(宏队列)
  7. watchEffect 4
  8. watch 4 2

3、判断

API含义
isProxy判断某个数据是否是由reactivereadonly
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
}

博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部