在Vue中异步请求传递到子组件props中出现_ob_:Observer
引言:有时候,当我们在父组件中调用异步请求去请求数据的并把请求到的数据传递给子组件的props时,
会发现子组件中拿不到值,没有响应,watch也监视不到,使用深度(deep)立即(immediate)监
视(watch)也只是得到一个不可遍历的_ob_:Observer
看如下代码:
父组件
<template>
<div>
<Page :pageData="pageData" @pageClick="pageClick" ref="child"></Page>
</div>
</template>
<script>
data(){
return{
pageData: {},
};
}
methods:{
/**
* 获取记录
*/
weekLog(currentPage) {
let tmpObj = ...;
//看如下代码
this.log.weekLog(tmpObj).then((res) => {
this.initPageData(res);
});
},
/**
* 初始化pageData
*/
initPageData(res) {
// let a = {};
// a.totalPages = res.data.pageNum;
// a.currentPage = this.currentPage;
// a.pagerCount = this.pagerCount ? this.pagerCount : 7;
// this.pageData = a;
// this.$set(this.pageData, "totalPages", res.data.pageNum);
// this.$set(this.pageData, "currentPage", this.currentPage);
// this.$set(this.pageData, "pagerCount", 7);
this.pageData.totalPages = res.data.pageNum;
this.pageData.currentPage = this.currentPage;
this.pageData.pagerCount = this.pagerCount ? this.pagerCount : 7;
console.log(this.pageData.totalPages);
},
}
<script>
子组件:
<template>
<div class="page">
</div>
</template>
<script>
import { Pagination } from "@/api/extendsion/pages/index.js";
export default {
props: {
pageData: {
type: Object,
required: true,
default: function () {
return null;
},
},
},
watch: {
pageData: {
handler(newVal, oldVal) {
console.log(newVal, oldVal); //_ob_:Observer undefined
console.log(this.pageData.totalPages); //undefined
},
deep: true,
immediate: true,
},
},
};
</script>
当weekLog请求成功后,调用initPageData方法将值传递到了pageData中,同时也传递到了子组件的pageData中(理论上),但是在子组件中打印却出现_ob_:Observer undefined
(在watch中,因为这里并没有在HTML标签内使用模版语法以及其他响应式操作,而是由pageData的改变去调用某些函数,所以没有使用生命周期钩子),pageData值改变,watch也监视不了,点开可以看到值,但是如果去访问的话访问不了,都是undefined,如下:
尝试的网上的一些方法,比如说:
JSON.parse(JSON.stringify(值))
Object.assign({},this.owner)
以上两种方法都没什么用,也有可能是对我来说没什么用
认为异步导致错误
一开始以为是异步导致数据传递的问题,网上查了一些关于_ob_:Observer
的资料,都说是数据还没赋值给变量,就开始访问了,导致访问不到
就比如,在我的代码中,当weekLog异步请求之后,将请求到的值赋给了pageData,值还没有传递到子组件中,就访问子组件props的pageData,因为Vue更新是异步的,所以不排除有这种可能。
然后,我又尝试了一下两种方法:
-
第一种:调用子组件的方法
-
我在子组件中声明一个方法,每次请求并赋值完后,调用一下,不就可以访问到了
-
weekLog(currentPage, pageCount) { this.log.weekLog(tmpObj).then((res) => { this.initPageData(res) this.$refs.child.childInit(); }); },
-
第一种方法的确有用,但是违背了组件的独立性(个人认为),不可能每次调用的时候,都在一个异步回调中调用一个指定的方法
-
-
第二种:setTimeOut
- 使用定时器,在一定时间后访问,这个也可以访问到,但是不确定因素太多了,比如说:异步请求的时间,网络等等之类的。
实例创建之后添加属性
之后,我发现根本问题并不在异步,而是数据根本就没有进行传递,也就是pageData并不是一个响应式数据,导致watch监视不到,这是为什么呢?
收集资料后发现,我在父组件中定义pageData为空对象
pageData:{}
之后的方法initPageData实则是为pageData添加了三个属性
官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新
这个对象内并没有为三个属性添加getter和setter,只有这两个控制器存在时,才能触发响应式更新
解决方法:
-
一开始就声明好属性,如下:
-
pageData:{ currentPage:0, pagerCount:0, totalPages:0, }
-
-
添加属性时使用Vue.$set
-
this.$set(this.pageData, "totalPages", res.data.pageNum); this.$set(this.pageData, "currentPage", 7); this.$set(this.pageData, "pagerCount", 1);
-