vue中父组件异步数据通过props方式传递给子组件,子组件接收不到的问题

简介: vue中父组件异步数据通过props方式传递给子组件,子组件接收不到的问题

问题描述

组件化开发中经常用到父子组件的通信,父传子子传父等数据的操作,如果父组件的数据是发请求从后端获取的异步数据,那么父组件将这个数据传递给子组件的时候,因为是异步数据,就会出现父组件传递过去了,但是子组件mounted钩子初始情况下是接收不到的问题。本篇文章记录了一下这个问题的解决方案。

在说这个问题之前,我们先来回顾一下父子组件的生命周期

父子组件生命周期执行顺序

加载渲染数据过程

父组件 beforeCreate -->

父组件 created -->

父组件 beforeMount -->

子组件 beforeCreate -->

子组件 created -->

子组件 beforeMount -->

子组件 mounted -->

父组件 mounted -->

更新渲染数据过程

父组件 beforeUpdate -->

子组件 beforeUpdate -->

子组件 updated -->

父组件 updated -->

销毁组件数据过程

父组件 beforeDestroy -->

子组件 beforeDestroy -->

子组件 destroyed -->

父组件 destroyed

可以这样理解,父组件生命周期中会先看看子组件的生命周期有没有走完,子组件生命周期走完了,才会走父组件的生命周期。

问题分析

我们模拟一下父子组件通信的过程,写个小demo。看看在子组件中的mounted钩子中能不能接收到父组件传递过来的数据

父组件代码

<template>
  <div id="app">
    <child :msg="msg"></child>
  </div>
</template>

<script>
import child from "./views/child";
export default {
  name: "App",
  components: {
    child,
  },
  data() {
    return {
      msg: "", // 我们要把父组件从接口获取的数据存到data中的msg里面,然后再传递给子组件
    };
  },
  created() {
    // 用定时器模拟发请求异步获取后端接口的数据
    setTimeout(() => {
      this.msg = "666";
    }, 200);
  },
};
</script>

子组件代码

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

<script>
export default {
    props:{
        msg:{
            type:String,
            default:''
        }
    },
    mounted() {
        console.log('mounted钩子中接收',this.msg);
    },
}
</script>

最终在mounted钩子中会实现,我们会发现打印不出来,如下图

image.png

当然如果是同步的数据传递给子组件,子组件的mounted钩子是能接收到,能打印出来的,这里就不演示了,因为我们做项目开发的数据大多数都输从后端的接口中获取的异步数据的。

因为父组件传递给子组件的数据,可能我们还要加工一下再使用,所以在mounted钩子中获取父组件传递过来的数据是一定要做的。那么,这里为什么mounted钩子中打印不出来父组件传递过来的数据,但是props最终接收到了,页面最终还渲染出来了么?

原因浅析

我们知道,mounted钩子默认加载只会执行一次,由于数据是要等到200毫秒以后才能拿到,那么子组件的mounted钩子执行的时候,还没有拿到父组件传递过来的数据,但是又必须要打印出来this.msg的结果,那这样的话,就只能去打印props中的msg的默认值空字符串了,所以打印的结果是一个空字符串,比如,我们在子组件中这样打印就知道this.msg是不是空字符串了

mounted() {
        console.log('mounted钩子中接收', this.msg == '');
    },

打印结果图如下

image.png

但是props是可以等的,是可以拿到异步的数据渲染的。所以就出现了上述的结果,有问题解决问题,接下来说一下解决这样的问题的方案

方案一 使用v-if控制子组件渲染的时机

思路其实很简单,就是初始还没拿到后端接口的异步数据的时候,不让组件渲染,等拿到的时候再去渲染组件。使用v-if="变量"去控制,初始让这个变量为false,这样的话,子组件就不会去渲染,等拿到数据的时候,再让这个变量变成true,这样的话,组件就会去渲染,此时数据也已经得到了,这样的话,在子组件的mounted钩子中就拿到父组件传过来的异步数据了。代码如下

父组件

<template>
  <div id="app">
    <child :msg="msg" v-if="isGetData"></child>
  </div>
</template>

<script>
import child from "./views/child";
export default {
  name: "App",
  components: {
    child,
  },
  data() {
    return {
      msg: "",
      isGetData:false // 初始为false,就不会被渲染对应的子组件
    };
  },
  created() {
    // 用定时器模拟发请求异步获取后端接口的数据
    setTimeout(() => {
      this.msg = "666";
      this.isGetData = true // 拿到数据以后,再把isGetData置为true,这样的话,组件就会被渲染啦,数据也就会被传递过去啦
    }, 200);
  },
};
</script>

子组件

这种方式,子组件不用动代码,在父组件中去做控制即可

但是这种方式有一个小小的缺点,就是最终效果会显得组件有些延迟才出现效果。因为异步数据是从后端的接口获取的,如果接口时间长一些的话,最终效果渲染也会慢一点,但是!!!一般情况下,后端的接口速度都会控制在几十到几百毫秒的时间,一般情况下,不会出现好几秒,甚至几十秒的接口,所以瑕不掩瑜,这种方式不影响我们使用

方案二 子组件使用watch监听父组件传递过来的数据

父组件

这种方式父组件正常传递数据即可,不需要做什么代码处理,只要在子组件中加一个监听即可

子组件

<template>
  <div>
    <h2>{{ editMsg }}</h2>
  </div>
</template>

<script>
export default {
  props: {
    msg: {
      type: String,
      default: "",
    },
  },
  watch: {
    // 监听到父组件传递过来的数据后,加工一下,
    // 存到data中去,然后在页面上使用
    msg(newnew, oldold) {
      console.log("监听", newnew, oldold);
      this.editMsg = "---" + newnew + "---";
    },
  },
  data() {
    return {
      editMsg: "",
    };
  },
};
</script>

看一下这种方式对应的效果图

image.png

看被加工的父组件传递过来的数据

方案三 不使用props方式父子组件通信

比如使用事件总线、使用vuex,不过一般情况下,父子组件通信都是使用props通信,所以,解决问题的方式,方案一、方案二任选一种即可。

相关文章
|
6月前
|
JavaScript API
vue使用hook:声明周期来监听子组件的声明周期
本文介绍了如何在Vue中使用生命周期钩子来监听子组件的生命周期事件,包括在子组件内部监听和在父组件中监听子组件的生命周期钩子。
80 0
|
5月前
|
JavaScript
Vue 的父组件和子组件生命周期钩子执行顺序
在 Vue 中,父组件和子组件的生命周期钩子执行顺序如下:
|
5月前
|
监控 JavaScript 开发者
在 Vue 中,子组件为何不可以修改父组件传递的 Prop,如果修改了,Vue 是如何监控到属性的修改并给出警告的
在 Vue 中,子组件不能直接修改父组件传递的 Prop,以确保数据流的单向性和可预测性。如果子组件尝试修改 Prop,Vue 会通过响应式系统检测到这一变化,并在控制台发出警告,提示开发者避免这种操作。
|
5月前
|
JavaScript
vue3,使用watch监听props中的数据
【10月更文挑战第3天】
2731 2
|
JavaScript 前端开发
模拟Vue数据的双向绑定
Vue的数据双向绑定功能一直为人称道, Vue数据的双向数据绑定主要依赖了Object.defineProperty,这里尝试用最简单的代码, 实现数据的双向绑定Demo MVVM ViewModel基本实现原理 Gi...
958 0
|
3月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
177 1
|
22天前
|
JavaScript 前端开发 算法
vue渲染页面的原理
vue渲染页面的原理
97 56
|
12天前
|
数据采集 资源调度 JavaScript
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
|
12天前
|
存储 数据采集 供应链
属性描述符初探——Vue实现数据劫持的基础
属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
1月前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。

热门文章

最新文章