Vue.js 中父级数据更改时如何重新渲染内部组件

Posted

技术标签:

【中文标题】Vue.js 中父级数据更改时如何重新渲染内部组件【英文标题】:How to re-render inner component when data from parent changes in Vue.js 【发布时间】:2021-11-28 05:01:08 【问题描述】:

我试图在父组件中更新某些值时从 API 获取一些数据,然后在子组件中使用它。我尝试了几件事,但都没有成功。

这是我的组件的简化版本:

家长

<template lang="html">
<div id="wrapper">
    <h4>My Super Component</h4>
    <button v-on:click="setListID">Load another list</button>
    <ChildComponent :usernames="usernames"></ChildComponent>
</div>
</template>

<script>
import ChildComponent from "./ChildComponent.vue"

export default 
    components: 
        ChildComponent
    ,
    data() 
        return 
            listID: 0,
            usernames: undefined,
        
    ,
    watch: 
        listID: function(newID) 
            this.usernames = getUsernames(newID)
        
    ,
    methods: 
        setListID() 
            let id = +prompt("Input the list ID");
            if (Number.isNaN(id)) 
                alert("Please input a valid number");
             else 
                this.listID = id;
            
        
    ,
    async mounted() 
        this.usernames = await getUsernames(this.listID)
    


function sleep(ms) 
    return new Promise(resolve => setTimeout(resolve, ms));


// Simulating an API call
async function getUsernames(listID) 
    sleep(200).then(() => 
        switch (listID) 
            case 0:
                return ['Pierre', 'Paul', 'Jaques']
            case 1:
                return ['Riri', 'Fifi', 'Loulou']
            case 2:
                return ['Alex', 'Sam', 'Clover']
            default:
                return []
        
    )

</script>

儿童

<template lang="html">
    <p v-for="username in usernames">username</p>
</template>

<script>
export default 
    props: 
        usernames: Object
    ,

</script>

我在孩子身上得到的道具是一个承诺,我试图传递一个数组,但由于获取数据的函数是异步的,我不能等待手表,我有点卡住了。

更新:

我认为问题来自此代码:

// Simulating an API call
async function getUsernames(listID) 
    await sleep(200).then(() => 
        switch (listID) 
            case 0:
                return ['Pierre', 'Paul', 'Jaques']
            case 1:
                return ['Riri', 'Fifi', 'Loulou']
            case 2:
                return ['Alex', 'Sam', 'Clover']
            default:
                return []
        
    )
    return 'returned too early'

函数总是返回'returned too early'。当我删除这个默认返回时,undefined 被返回并且我的子组件使用它作为数组。

【问题讨论】:

您没有在 v-for 中使用 :key 属性。但无论如何,我认为在需要时重新渲染子组件的最佳方法是使用 $forceUpdate 我已经尝试使用$forceUpdate,但我认为我没有正确使用它。能给我举个例子吗? 试试这个话题:michaelnthiessen.com/force-re-render 是我关注的那个lol,没用 一侧节点,使用 await 或 .then,但不能同时使用。 【参考方案1】:

尝试如下 sn-p

Vue.component('Child', 
  template: `
    <div class="">
      <p v-for="username in usernames">username</p>
    </div>
  `,
  props: 
    usernames: Array
  ,
)

new Vue(
  el: '#demo',
  data() 
    return 
      listID: 0,
      usernames: undefined,
    
  ,
  watch: 
    listID: async function(newID) 
      this.usernames = await this.getUsernames(newID)
    
  ,
  methods: 
    setListID() 
      let id = +prompt("Input the list ID");
      if (Number.isNaN(id)) 
        alert("Please input a valid number");
       else 
        this.listID = Number(id);
      
    ,
    sleep(ms) 
      return new Promise(resolve => setTimeout(resolve, ms));
    ,
    getUsernames(listID) 
      return this.sleep(200).then(() => 
        switch (listID) 
            case 0:
                return ['Pierre', 'Paul', 'Jaques']
            case 1:
                return ['Riri', 'Fifi', 'Loulou']
            case 2:
                return ['Alex', 'Sam', 'Clover']
            default:
                return []
        
      )
    
  ,
  async mounted() 
    this.usernames = await this.getUsernames(this.listID)
  
)

Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div id="wrapper">
    <h4>My Super Component</h4>
    <button v-on:click="setListID">Load another list</button>
    <Child :usernames="usernames"></ChildComponent>
</div>
</div>

【讨论】:

【参考方案2】:

似乎与您发送数组的道具有关,但在您期望对象的子组件中。 试试下面的代码看看

<template lang="HTML">
  <p v-for="(username, index) in usernames" :key="index">username</p>

</template>

<script>
export default 
    props: 
        type: Object, // or Aarray
        default: () => 
          return  // [] if the type is array
        
    ,

</script>

【讨论】:

它也不起作用

以上是关于Vue.js 中父级数据更改时如何重新渲染内部组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue JS 2. 如何防止在两个父级之间导航时重新加载相同的嵌套组件?

Vue.js - 父级基于无渲染子数据生成组件

从 vue.js 3 中传递数据的方法渲染组件

避免直接改变道具,因为每当父组件重新渲染时,该值都会被覆盖

在 React 中通过更改父级的道具来更新子组件

如果子组件发生更改,如何重新渲染父组件