vue2在子组件的data中获取不到props中的值,或者一直是默认值(父组件的值来自异步)

复现问题

为了方便我直接在main.js中使用mockjs模拟一个接口请求并为其设置了2秒的响应时间

mian.js

import Vue from "vue";
import App from "./App.vue";

const Mock = require("mockjs");
// 请求的响应时间2秒
Mock.setup({
    timeout: "2000",
});

// 请求方式要使用小写
Mock.mock("/test", "get", {
    "msg|1-10": "★",
});

Vue.config.productionTip = false;

new Vue({
    render: (h) => h(App),
}).$mount("#app");
父组件中将自己的msg传递给子组件,父组件中的msg来自于接口异步任务。

父组件

<template>
  <div>
    <HelloWorld :msg="msg" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
import axios from "axios";
export default {
  name: "App",
  data() {
    return {
      msg: "默认值",
    };
  },
  components: {
    HelloWorld,
  },
  created() {
    axios({
      method: "get",
      url: "/test",
    }).then(response => {
      console.log(response, "response");
      this.msg = response.data.msg;
    });
  },
};
</script>

<style></style>

子组件接收msg并展示

子组件

<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  data() {
    return {
      msgSon: this.msg,
    };
  },
  mounted(){
    setInterval(() =>{
      console.log(this.msgSon)
    },1000)
  }
};
</script>

<style scoped></style>

运行效果
在这里插入图片描述

一开始输出“默认值”没错,但是我们发现接口返回之后,父组件的msg已经修改了,但是
子组件还是一直输出“默认值”。

分析原因

因为把props的值赋值给data不是响应式的,props中的值改变了,data中的值不会
响应式更改。回到我们的文章标题:data中获取不到props中的值,可能大家在父组件
中设置的值为undefined,但是大家又觉得我明明在接口响应中给它赋值了,所以大家
觉得是子组件props没有获取到值什么的,其实只是因为在子组件渲染的时候,props
会去父组件中获取值,但是父组件此时的值在接口中还没有返回,所以只是默认值。

解决方案

使用watch

站在子组件的角度思考:不就是父组件值改了,但是我子组件不知道嘛,没关系,vue为
我们提供了watch,可以监听一个值是否变化,我用watch监听你父组件传给我的值,你一
旦改了值,我就把我的data中复制出来的值也改了不就行了。
<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  data() {
    return {
      msgSon: this.msg,
    };
  },
  mounted() {
    setInterval(() => {
      console.log(this.msgSon);
    }, 1000);
  },
  watch: {
    msg: function (newVal) {
      this.msgSon = newVal;
    },
  },
};
</script>

<style scoped></style>

运行效果
在这里插入图片描述

使用v-if

站在子组件的角度思考:我渲染的时候需要拿值,但是你父组件还没有拿到真正的值,那
我就先不渲染呗,等你拿到真正的值了,再让我渲染,此时我拿到的值不就是真正的值了。
<template>
  <div>
    <HelloWorld :msg="msg" v-if="lock"/>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
import axios from "axios";
export default {
  name: "App",
  data() {
    return {
      msg: "默认值",
      lock: false,
    };
  },
  components: {
    HelloWorld,
  },
  created() {
    axios({
      method: "get",
      url: "/test",
    }).then(response => {
      console.log(response, "response");
      this.msg = response.data.msg;
      this.lock = true;
    });
  },
};
</script>

<style></style>

运行效果
在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiuJie_Boom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值