如何从异步的Promise外部获取then内的res,解决方法:最好用ref包数组(此处也尝试多种方式用reactive正确包裹数组)
问题描述:
-
由于在Vue2的data中的数据是响应式的,但Vue3在使用组合api的setup内的数据没有响应式,于是Vue3 提供实现响应式数据的方法ref和reactive 。
-
当axios请求数据时,使用了Promise,由于只能从then中获取数据。此时,就需要解决:
- 外部如何获取数据 - ref使用 - 若使用reacitive,如何正确用reacitive包裹数组以至于不失去响应式
认识ref
- 是 Vue3 中提供的实现响应式数据的方法。
- 操作普通数据类型,如数值、字符串、布尔值、数组,最好不要用在对象。
认识reactive
- reactive 是 Vue3 中提供的实现响应式数据的方法。
- 操作复杂数据类型,如对象。操作数组时有陷阱,下面有介绍规范。
- 在 Vue2 中响应式数据是通过 defineProperty 来实现的
- 在 Vue3 中响应式数据是通过 ES6 的 Proxy来实现的。
遇到的问题
- 当axios使用了Promise请求数据时是异步的,只能从then中获取数据,那么如何从then的外部获取数据。
- reactive直接接收数组会有陷阱,只能用push才不会失去响应性,如何使数据仍然是响应式数据,在模板中渲染。
解决方法
- 错误方法:使reactive直接接收一个空数组 []
//reactive直接接收数组会有陷阱,只能用push才不会失去响应性
const result = reactive([]);
getAllProduct().then((res)=>{
console.log('then内部的res',res.list);
result = res.list
})
console.log('then外部的result', result);
return {result}
显示结果:
then内部已经获取到数据了,但是外部的reactive的实例无法被更新,且模板中无法渲染出数据列表。
- 正确方式1:reactive里面传入对象(包含数组)
const result = reactive({
list: [],
});
getAllProduct().then((res) => {
console.log("then内部的res", res.list);
result.list = res.list;
});
console.log("then外部的result", result);
return { result };
执行结果:
模板中数据正确渲染,保持了响应式。console中正确打印出查询的数据,then的内部和外部都有正确的结果
- 正确方式2:解决传入空数组 [] 失去响应式问题,遍历获取的数据一个个使用push进创建的数组
const result = reactive([]);
getAllProduct().then((res) => {
console.log("then内部的res", res.list);
res.list.forEach((e) => {
result.push(e);
});
});
console.log("then外部的result", result);
return { result };
结果是正确的,模板中可渲染,且then外部正确接收到数据。
- 正确方式3:使用 ref 创建
const result = ref([]);
getAllProduct().then((res) => {
console.log("then内部的res", res.list);
result.value = res.list;
});
console.log("then外部的result", result);
return { result };
结果显示正确,模板中可渲染,且then外部正确接收到数据。
- 正确方式4:解决reactive传入空数组 [] 问题,使用扩展符… ,类似于遍历并push的简写
const result = reactive([]);
getAllProduct().then((res) => {
console.log("then内部的res", res.list);
result.push(...res.list)
});
console.log("then外部的result", result);
return { result };
结果显示正确,模板中可渲染,且then外部正确接收到数据。
总结
- 正确使用 reacitive 包裹数组方法
- 传入对象类型,因为reactive本来就接收对象类型数据
const result = reactive({list: []});
- 硬要直接传入空数组 [] ,
const result = reactive([]);
- 使用foreach遍历数组,push进目标数组
- 使用扩展符…,类似于上面的方法
- 传入对象类型,因为reactive本来就接收对象类型数据
- 还可以使用 ref 创建响应式数组,ref 本身是接收普通类型数据的,记得ref数据要.value