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

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

2024-08-15 22:08:45 前端知识 前端哥 724 307 我要收藏

1.问题描述:

父组件异步加载获取的数据,通过props的方式传递给子组件,子组件在mounted生命周期钩子函数中,初始情况接收不到的问题

首先使用express简单模仿一个接口

// 导入express模块
const express = require('express');
// 导入cors模块
const cors = require('cors');

// 创建express的服务器实例
const app = express();

// 路由模块
const router = express.Router();

// cors跨域
app.use(cors())

// 注册路由模块
app.use('/api', router)

router.get('/list', (req, res) => {
    const list = [
        {name: '张三', age: 18},
        {name: '李四', age: 20}
    ]
    res.send({
        code: 200,
        msg: '请求成功',
        data: list
    })
})

// 调用app.listen方法,指定端口号并启动web服务器
app.listen(80, () => {
    console.log('Express server running at http://127.0.0.1')
})

代码如下:

  • 父组件
<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios from "axios";
import Child from '@/components/Child.vue'

interface user {
  name: string,
  age: number
}

const userList = ref<user[]>([])
const getUserData = async () => {
  const res = await axios.get('http://localhost/api/list')
  userList.value = res.data.data
}

onMounted(() => getUserData())

</script>

<template>
  <div class="container">
    <p>我是父组件</p>
    <Child :userList="userList"></Child>
  </div>
</template>

<style scoped lang="scss">
.container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 600px;
  height: 400px;
  background: pink;
  p {
    text-align: center;
    font-size: 28px;
    font-weight: bold;
  }
}
</style>
  • 子组件
<script setup lang="ts">
import { onMounted } from "vue";

interface user {
  name: string,
  age: number
}

const props = defineProps<{
  userList: user[]
}>()

onMounted(() => {
  console.log(props.userList)
})

</script>

<template>
  <div class="child-container">
    <p>我是子组件</p>
    <ul>
      <li v-for="(item,index) in userList" :key="index">姓名{{ item.name }},年龄{{ item.age }}</li>
    </ul>
  </div>
</template>

<style scoped lang="scss">
.child-container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 300px;
  height: 200px;
  background: gray;
  p {
    text-align: center;
    font-size: 28px;
    font-weight: bold;
  }
  ul {
    margin-top: 20px;
  }
}
</style>

在Child子组件中,我们打印了props.userList父组件异步请求获取后,传递给子组件的数据,控制台打印结果如下:
在这里插入图片描述
我们发现数组长度为0,并不是后端返回的数据。

2.问题产生原因

我们分别在父子组件onMounted生命周期中打印信息,查看结果:结果如下
在这里插入图片描述
我们发现,先打印子组件挂载,后父组件挂载。
原因解释:由于userList是异步请求获取的,需要时间。而子组件又先挂载,此时父组件userList需要一段时间才能获取到,所以打印出来的是父组件userList的默认值,即空数组。

3.解决方案

3.1使用v-if控制子组件渲染的时机

代码如下:

<Child v-if="userList && userList.length > 0" :userList="userList"></Child>

此时控制台打印结果如下:
在这里插入图片描述
此时父组件先挂载,然后子组件挂载。只有当父组件请求获取到异步数据之后,再开始渲染子组件,这样在子组件onMounted生命周期中就可以拿到父组件异步请求传递的数据了。

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

代码如下:

watch(() => props.userList, (newValue, oldValue) => {
  console.log(newValue,oldValue)
})

控制台打印结果如下:
在这里插入图片描述
因为子组件先挂载,此时父组件异步请求获取过来的数据一开始为默认值,即[],然后父组件异步请求获取到了数据,即长度为2的数组,所以打印以上内容。现在就可以在watch回调的newValue,对userList进行操作,就不会像子组件onMounted生命周期一开始是空数组的情况。
代码如下:

watch(() => props.userList, (newValue, oldValue) => {
  newValue.push({name: '王五', age: 22})
})

页面展示如下:
在这里插入图片描述

4.问题来源

在父组件中引入子组件,子组件用于展示echarts图表,为了减少请求次数,父组件发请求,然后传递给多个子组件,进行数据展示。子组件在onMounted生命周期中进行setOptions配置,发现父组件传递的数据为空数组,子组件图表未能正确展示。当然也可以子组件分别进行网络请求,但是同一个接口会请求多次。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/15738.html
标签
评论
发布的文章

HTML5学习记录

2024-04-29 12:04:01

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!