admin管理员组

文章数量:1289603

Trying out VueJS 2.0 RC, and using the fetch API to load some data for some of the ponents. Here's a mock example:

const Component = {
  template: '#p',
  name: "some-ponent",
  data: function () {
    return {
      basic: data.subset,
      records: function () {
        return fetch('/datasource/api', {
          method: 'get'
        }).then(function (response) {
          return response.json();
        }).then(function (response) {
          if (response.status == "success") {
            return response.payload;
          } else {
            console.error(response.message);
          }
        }).catch(function (err) {
          console.error(err);
        });
      }
    }
  }
};

The data object is a global application state, defined before the app's initialization, and only a subset of it is needed in the ponent, hence that part. The main set of the ponent's data es from another endpoint which I'm trying to call. However, the data property expects an object, and it's getting back a Promise it can't really use in the context of a loop in the template for rendering etc (e.g. v-for="record in records")

Am I going about this the wrong way? What's the approach to get the data records property to update once it's fully fetched? Is there a way to force the code to stop until the promise resolves (effectively making it sync)? The ponent is useless without the data anyway, so there's a waiting period before it can be used regardless.

What is the right way to asynchronously populate a ponent's data field without using plugins like vue-async or vue-resource?

(I know I could use the XHR/jQuery methods of non-promise ajax calls to do this, but I want to learn how to do it using fetch)


Update: I tried defining a created hook, and a method to load the data, like this but no dice - in my own experiments, the records property fails to update once it's loaded. It doesn't change, even though the data is successfully fetched (successfully logs into console).

Could have something to do with me using vue-router and the ponent I'm dealing with triggering when a link is clicked, as opposed to being a regular Vue ponent. Investigating further...


Update #2: If I continue investigating the jsfiddle approach above and log this.records and response.payload to the console, it shows the records object being populated. However, this doesn't seem to trigger a change in the template or the ponent itself - inspecting with Vue dev tools, the records property remains an empty array. Indeed, if I add a method logstuff and a button into the template which calls it, and then have this method log this.records into the console, it logs an observer with an empty array:

Now I'm wondering why the data property of a ponent would be not updated even after it's explicitly set to another value. Tried setting up a watcher for $route that triggers the reload method, but no dice - every subsequent load of that route does indeed re-issue the fetch, and the console logs this.records as populated (from within fetch), but the "real" this.records remains an empty array.

Trying out VueJS 2.0 RC, and using the fetch API to load some data for some of the ponents. Here's a mock example:

const Component = {
  template: '#p',
  name: "some-ponent",
  data: function () {
    return {
      basic: data.subset,
      records: function () {
        return fetch('/datasource/api', {
          method: 'get'
        }).then(function (response) {
          return response.json();
        }).then(function (response) {
          if (response.status == "success") {
            return response.payload;
          } else {
            console.error(response.message);
          }
        }).catch(function (err) {
          console.error(err);
        });
      }
    }
  }
};

The data object is a global application state, defined before the app's initialization, and only a subset of it is needed in the ponent, hence that part. The main set of the ponent's data es from another endpoint which I'm trying to call. However, the data property expects an object, and it's getting back a Promise it can't really use in the context of a loop in the template for rendering etc (e.g. v-for="record in records")

Am I going about this the wrong way? What's the approach to get the data records property to update once it's fully fetched? Is there a way to force the code to stop until the promise resolves (effectively making it sync)? The ponent is useless without the data anyway, so there's a waiting period before it can be used regardless.

What is the right way to asynchronously populate a ponent's data field without using plugins like vue-async or vue-resource?

(I know I could use the XHR/jQuery methods of non-promise ajax calls to do this, but I want to learn how to do it using fetch)


Update: I tried defining a created hook, and a method to load the data, like this but no dice - in my own experiments, the records property fails to update once it's loaded. It doesn't change, even though the data is successfully fetched (successfully logs into console).

Could have something to do with me using vue-router and the ponent I'm dealing with triggering when a link is clicked, as opposed to being a regular Vue ponent. Investigating further...


Update #2: If I continue investigating the jsfiddle approach above and log this.records and response.payload to the console, it shows the records object being populated. However, this doesn't seem to trigger a change in the template or the ponent itself - inspecting with Vue dev tools, the records property remains an empty array. Indeed, if I add a method logstuff and a button into the template which calls it, and then have this method log this.records into the console, it logs an observer with an empty array:

Now I'm wondering why the data property of a ponent would be not updated even after it's explicitly set to another value. Tried setting up a watcher for $route that triggers the reload method, but no dice - every subsequent load of that route does indeed re-issue the fetch, and the console logs this.records as populated (from within fetch), but the "real" this.records remains an empty array.

Share Improve this question edited Aug 29, 2016 at 10:33 Swader asked Aug 28, 2016 at 22:51 SwaderSwader 11.6k15 gold badges53 silver badges86 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

The solution was the jsfiddle approach, with a twist. This part:

reload: function () {
      fetch('/data/api', {
        method: 'get'
      }).then(function (response) {
        return response.json();
      }).then(function (response) {
        if (response.status == "success") {
          this.records = response.payload;
        } else {
          console.error(response.message);
        }
      }).catch(function (err) {
        console.error(err);
      });
    }

needed a .bind(this) in the part which sets the this.records value after the fetch, like so:

reload: function () {
      fetch('/data/api', {
        method: 'get'
      }).then(function (response) {
        return response.json();
      }).then(function (response) {
        if (response.status == "success") {
          this.records = response.payload;
        } else {
          console.error(response.message);
        }
      }.bind(this)).catch(function (err) {
        console.error(err);
      });
    }

This post was what made it click for me.

Lesson learned: in modern JS, always keep scope in mind.

本文标签: javascriptVueJS async component data and promisesStack Overflow