异步调用计算属性 - Vue.js

4

我有一个计算属性,只有在存在属性匹配时才会使用。因此,我正在进行异步调用以便仅在需要时检索数据。但是,我尝试使异步调用返回计算属性的数据时遇到了问题。

以下是我的代码:

new Vue({
    el: "#formCompleteContainer",
    data: {
        form: {},
        components: []
    },
    computed: {
        employeeList: function () {
            var self = this;
            if (_.some(this.components, function (component) {
                return component.ComponentInfo.Type === 8
            })) {
                var employees = [];
                $.ajax({
                    url: "/Form/GetAllUsers",
                    type: "GET"
                }).done(function (results) {
                    employees = results;
                });

                return employees;
            } else {
                return [];
            }
        }
    }
});

我知道这不起作用是因为在调用完成之前我就返回了。我看到过如何使用deferred对象等,但似乎无法弄清如何在Vue中实现。


1
可能会有用的是 https://github.com/foxbenjaminfox/vue-async-computed。 - Daniel Beck
1
@DanielBeck 我决定不使用计算属性来完成我想做的事情。但是谢谢你提供的链接。我一定会查看它,也许在未来的项目中会用到它。 - Quiver
4个回答

2
这就是 vue-async-computed 的用途。它解决了你返回的 Promise 并处理任何竞争条件。
new Vue({
    el: "#formCompleteContainer",
    data: {
        form: {},
        components: []
    },
    asyncComputed: {
        employeeList: function () {
            if (_.some(this.components, function (component) {
                return component.ComponentInfo.Type === 8
            })) {
                return $.ajax({
                    url: "/Form/GetAllUsers",
                    type: "GET"
                });
            } else {
                return Promise.resolve([]);
            }
        }
    }
});

3
不需要第三方实现也可以使这个工作正常运行。 - T.Woody

1

经过进一步的研究,我已经选择了另一种方法。我同意Sphinx的观点,我认为使用计算属性无法实现我想要达到的目标。

相反,我采用了以下方案:

new Vue({
    el: "#formCompleteContainer",
    data: {
        form: {},
        components: [],
        employees: []
    },
    methods: {
        getEmployees: function () {
            var self = this;
            if (_.some(this.components, function (component) {
               return component.ComponentInfo.Type === 8;
            })) {
                $.ajax({
                    url: "/Form/Form/GetAllUsers",
                    type: "GET"
                }).done(function (results) {
                    self.employees = results;
                });
            }
        }
    },
    created: function () {
        this.form = pageModel.Form;
        this.components = pageModel.Components;
    },
    mounted: function () {
        this.getEmployees();
    }
});

1

针对您的使用情况,我认为计算属性无法实现目标。

我的解决方案:

  1. 创建一个数据属性作为“延迟”对象,
  2. 然后使用一个观察器异步调用后端以获取新数据,并最终分配给延迟对象

就像下面的演示:

Vue.config.productionTip = false
app = new Vue({
  el: "#app",
  data: {
    product: "Boots",
    deferedProduct: ''
  },
  watch: {
    product: function (newVal, oldVal) {
      setTimeout(() => {
        this.deferedProduct = 'Cats in ' + newVal + '!'
      }, 1500)
    }
  },
  methods: {
    nextProduct: function () {
      this.product += 'a'
    }
  }
})
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app">
  <button @click="nextProduct()">Click Me!</button>
    <h2>{{product}}</h2>
    <h2>{{deferedProduct}}</h2>
</div>


0

正如已经指出的那样,mounted和其他第三方解决方案是可行的。

然而,为了更好的可读性和组件加载,将所需的Promise放置在data属性中会更好。然后使用Vue生命周期钩子created,我们可以使用.then等待该Promise解析。

例如:

requestService.js:

...
   async foo(){
      let myRequest = someRequest.createInstance()
      await myRequest.onReady()
      return myRequest.getSomePromise()
   } 
...

然后将服务import到您的组件中,并声明一个data属性:

myComponent.vue

...
   data: (){
      myPromiseLoc: null,
   }
...
   created: (){
      requestService.foo().then( result =>
      {
         this.myPromiseLoc = result
      }
   }
...

当组件加载时,此操作仅执行一次请求。任务是仅在显示类型为8的组件时加载数据。 - Michael2
@Michael2 具体的使用情况总是不同的。这个问题和实际问题都与async/await、promises和生命周期钩子有关。这个答案很好地概括了用户的实际问题。 - T.Woody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接