13

I'm sending 2 api requests before render the page:

const Profile = {
    template: '#profile',
    attributes: null,
    photos: [],
    data: function () {
        return {attributes: Profile.attributes, photos: Profile.photos};
    },
    beforeRouteEnter: function (to, from, next) {
        function getProfile() {
            return axios.get('user/get-profile?access-token=1', {responseType: 'json'});
        }
        function getPhotos() {
            return axios.get('photos?access-token=1', {responseType: 'json'});
        }

        axios.all([getProfile(), getPhotos()])
            .then(axios.spread(function (profile, photos ) {
                console.log(profile, photos );
                next(vm => {
                    vm.setProfile(profile);
                    vm.setPhotos(photos);
                })
            }));
    },
    methods: {
        setProfile: function (response) {
            Profile.attributes = response.data;
            console.log(Profile.attributes);
        },
        setPhotos: function (response) {
            Profile.photos = response.data;
            console.log(response);
        },           
    }
};

The problem is rendering occures before setProfile and setPhotos methods. How to correct render my component?

3 Answers 3

18

As mentioned in the comments, the first async/await solution is a little bit misleading, because all lifecycle methods are synchronous. This works, because the code is transpiled to an synchronous function with an IIFE inside.

Below I have added a few more recent snippets.

Old answer

Try it with async/await. I've removed beforeRouteEnter, axios.spread and added create.

const Profile = {
  template: '#profile',
  attributes: null,
  photos: [],
  data() {
    return {
      attributes: null,
      photos: null,
    };
  },
  async created() {
    const getProfile = await axios.get('user/get-profile?access-token=1');
    const getPhotos = await axios.get('photos?access-token=1');

    this.setProfile(profile);
    this.setPhotos(photos);
  },
  methods: {
    setProfile(response) {
      this.attributes = response.data;
      console.log(this.attributes);
    },
    setPhotos(response) {
      this.photos = response.data;
      console.log(response);
    },
  },
};

Shorter

const Profile = {
  template: '#profile',
  attributes: null,
  photos: [],
  data() {
    return {
      attributes: null,
      photos: null,
    };
  },
  async created() {
    this.attributes = await axios.get('user/get-profile?access-token=1');
    this.photo = await axios.get('photos?access-token=1');
  },
};

Updated answer

You can use an async function inside your lifecycle method.

const Profile = {
  template: '#profile',
  attributes: null,
  photos: [],
  data() {
    return {
      attributes: null,
      photos: null,
    };
  },
  created() {
    const fetchData = async () => {
      const { data: attributes } = await axios.get(
        'user/get-profile?access-token=1'
      );
      const { data: photos } = await axios.get('photos?access-token=1');

      this.attributes = attributes;
      this.photos = photos;
    };

    fetchData();
  },
};

Vue 3 and setup()

In Vue 3 you can use async setup(). If you use this, you must wrap your component with Suspense. Caution! This API is currently experimental https://vuejs.org/guide/built-ins/suspense.html#suspense=.

<Suspense>
  <template #default>
    <YourComponent />
  </template>
  <template #fallback>
    <div>Loading ...</div>
  </template>
</Suspense>
export default {
  name: 'YourComponent',
  async setup() {
    const { data: attributes } = await axios.get('user/get-profile?access-token=1');
    const { data: photos } = await axios.get('photos?access-token=1');

    return {
      attributes,
      photos
    }
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

function async created() not running
Strange. I've tested it 5 min ago. Maybe the async/await feature is not supported by your browser. Use babeljs to transpile it.
All the lifecycle events of the vuejs components are sync. They cannot be async, at least by v2.6.
2

You should just be able to return the Promise that is returned from calling axios.all like:

return axios.all([getProfile(), getPhotos()])
// .then() => ...

Or you could add a property to the data object and use this to show a loader until all Promises have resolved

const Profile = {
    template: '#profile',
    attributes: null,
    photos: [],
    data: function () {
        return {attributes: Profile.attributes, photos: Profile.photos, isLoading: true};
    },
    beforeRouteEnter: function (to, from, next) {
        function getProfile() {
            return axios.get('user/get-profile?access-token=1', {responseType: 'json'});
        }
        function getPhotos() {
            return axios.get('photos?access-token=1', {responseType: 'json'});
        }

        axios.all([getProfile(), getPhotos()])
            .then(axios.spread(function (profile, memes) {
                console.log(profile, memes);
                this.isLoading = false

                next(vm => {
                    vm.setProfile(profile);
                    vm.setPhotos(photos);
                })
            }));
    },
    methods: {
        setProfile: function (response) {
            Profile.attributes = response.data;
            console.log(Profile.attributes);
        },
        setPhotos: function (response) {
            Profile.photos = response.data;
            console.log(response);
        },           
    }
};

Template code omitted, but you can just switch the content you display based on the isLoading. If you go down this route then probably best to create an abstraction for the loader.

I would also suggest you might want to look at vuex rather than coupling all of your data to any specific component state.

Comments

0

Maybe This can help someone:

Try Promise:

let fetchData = new Promise((resolve, reject) => {
    axios.get(YOUR_API)
            .then(function (response) {
                resolve();
            })
            .catch(function () {
                reject('Fail To Load');
            });
});

fetchData.then(
    function(success) {
        YOUR_SUCCESS_LOGIC
    },
    function(error) {
        console.log(error);
    }
);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.