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

时间:2018-02-25 15:25:24

标签: javascript asynchronous vue.js vuejs2 vue-component

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

情况

我从其他API加载数据。我使用javascript原型语法创建了一个类来创建一个名为DataLoader的类,它处理所有加载和内部状态更改。通常,加载的数据以重复的方式显示(例如列表或卡片)。为此,我创建了一个名为DataLoaderWrapper的新组件,将DataLoader对象作为属性。 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对象有时是动态生成的,因此对对象实例的最直接访问是通过组件绑定属性实现的。 (我也试过直接访问加载器并发现没有不同的行为,但这种方式使得组件更容易用于我)

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

想象一下,你有一个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绑定是单向的,而子组件中的更新不会触发父更新。

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

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

我该怎么做?

1 个答案:

答案 0 :(得分:1)

问题是getArtistsLoader不会同步返回数据

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

所以在DataLoaderWrapper内,对于dataLoader props

,它是未定义的

解决方案

DataLoaderWrapper可以接受promise作为数据,因此可以在承诺解决后更新。

1。更新DataLoaderWrapper以接受承诺

我使用async道具来区分dataLoader是否异步

<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。 make getArtistsLoader返回承诺

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

3。添加async prop

<DataLoaderWrapper async :dataLoader="getArtistsLoader(release)">

完整演示

Edit vue async prop