javascript - vue.js - v-for 中动态生成的组件未正确更新绑定(bind)属性

标签 javascript asynchronous vue.js vuejs2 vue-component

我在 vue.js 中遇到了一个问题,我不知道该如何解决。我将尝试尽可能清楚和简短地解释它的要点。

情况

我从休息 API 加载数据。我使用 javascript 原型(prototype)语法创建了一个类来创建一个名为 DataLoader 的类。它处理所有加载和内部状态变化。通常情况下,加载的数据以重复的方式显示(例如列表或卡片)。我创建了一个名为 DataLoaderWrapper 的新组件为此,采取 DataLoader对象作为属性(property)。 DataLoaderWrapper根据 DataLoader 的加载状态显示加载微调器目的。此外,组件标记包括以下标记:

<slot :dataLoader='dataLoader' />

.. 允许轻松访问加载的数据。这个想法是像这样使用组件:
<DataLoaderWrapper :dataLoader="myDataLoader">
  <template slot-scope="props">
    <template v-for="item in props.dataLoader.data">
       {{item}}
    </template>
  </template>
</DataLoaderWrapper>

现在只是为了立即解决这个问题;我为什么要使用 props.dataLoader而不是 myDataLoader在模板内?基本思想是DataLoader对象有时是动态生成的,因此对对象实例的最直接访问是通过组件绑定(bind)属性。 (我也尝试过直接访问加载器并没有发现不同的行为,但这种方式使组件对我来说更容易使用)

现在让我们扩展这个基本概念。

假设你有一个 DataLoader配置为加载音乐发行列表的对象。这看起来像这样:
<DataLoaderWrapper :dataLoader="myReleaseLoader">
...
</DataLoaderWrapper>

此外,每个版本都由一位或多位艺术家出版。艺术家列表需要单独加载。我可以像这样扩展示例:
<DataLoaderWrapper :dataLoader="myReleaseLoader">
  <template slot-scope="props">
    <template v-for="release in props.dataLoader.data">
      <h1>release.Title</h1>
      Artists: 
      <DataLoaderWrapper :dataLoader="getArtistsLoader(release)">
        <template slot-scope="nestedProps">
          {{nestedProps.dataLoader.data.map(artist => artist.Name).join(', ')}}
        </template>
      </DataLoaderWrapper>
    </template>
  </template>
</DataLoaderWrapper>

问题

版本正确加载,模板myReleaseLoader正确呈现。一旦发生这种情况,一个新的 DataLoader实例是动态创建的,并命令为给定版本加载艺术家。每次发布都会发生这种情况。在加载艺术家加载器时,会显示加载微调器。问题是,nestedProps变量不会在 DataLoader 后立即更新实例完成加载数据。

我已经尝试解决这个问题至少两天了,这意味着我已经调试并检查了所有想到的东西。

我确信数据已正确加载并存在。但是 DataLoaderWrapper 的加载微调器组件仍在显示和打印 nestedProps.dataLoader揭示 data: []这与检查组件时显示的状态不符。这让我得出结论,nestedProps属性未正确更新。

我认为这可能是因为 vue 绑定(bind)是单向的,并且子组件中的更新不会触发父组件的更新。

每次在我的文件中保存更改而不执行页面的完全重新加载时,将页面加载到我的本地机器上并打开“热重载”会执行对 UI 的更新。现在更新 UI 时的加载器状态与第一次加载页面时的状态不同。数据不会再次加载,因为 getArtistsLoader(..)函数实现了一个缓存,它保证在请求时总是为给定的版本返回相同的加载器,这意味着在重新渲染页面时数据基本上已经存在,从而导致显示所需的输出。否则我无法进入正确的状态。

我尝试使用计算属性、直接访问加载器以及更直接地访问所需属性(例如 props.data 而不是 props.dataLoader.data ),但没有一个解决了更新问题。

我怎样才能做到这一点?

最佳答案

问题是 getArtistsLoader 不返回数据 同步

const data = getArtistsLoader(release);
// data === undefined

所以在DataLoaderWrapper里面, dataLoader Prop 未定义

解决方案

DataLoaderWrapper 可以接受 promise作为数据,所以它可以在 promise 解决时更新。

1.更新DataLoaderWrapper接受promise

我使用 async用于区分 dataLoader 是否异步的 Prop
<template>
  <div>
    <slot :dataLoader="realData"/>
  </div>
</template>

<script>
export default {
  props: {
    dataLoader: null,
    async: Boolean
  },
  data() {
    let realData = this.dataLoader;
    if (this.async) {
      realData = [];
      this.dataLoader
        .then(data => {
          this.realData = data;
        })
        .catch(error => {
          console.log(error);
        });
    }
    return {
      realData: realData
    };
  }
};
</script>

2. 让 getArtistsLoader 返回 promise
function getArtistsLoader(release) {
  retrun axios.get('/artists?release=' + release.id)
    .then((response) => response.data)
}

3.添加async支柱
<DataLoaderWrapper async :dataLoader="getArtistsLoader(release)">

完整演示

Edit vue async prop

关于javascript - vue.js - v-for 中动态生成的组件未正确更新绑定(bind)属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48975126/

相关文章:

linux - haproxy后面的nginx到静态html ssl获取真实IP地址

javascript - Chart JS — 条件水平行背景色

javascript - this 在 jQuery 中被转换为对象

node.js - Node.js 中的异步编程排序问题

javascript - 在VueJs中以CSV、Excel、PDF格式导出表格数据

vue.js - 在 Vue vs state 中创建全局变量

javascript - 更新期间控制复选框的最佳方法 | ReactJS

javascript - 将输入值应用于其所有 td innerhtml

javascript - 如何防止 ASP.net PageMethod 调用阻止其他 javascript 函数调用

javascript - 从 chrome.storage 顺序检索多个项目