【问题标题】:Fetching data from api before render component在渲染组件之前从 api 获取数据
【发布时间】:2018-02-19 16:38:19
【问题描述】:

我在渲染页面之前发送了 2 个 api 请求:

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);
        },           
    }
};

问题是渲染发生在setProfilesetPhotos 方法之前。如何正确渲染我的组件?

【问题讨论】:

    标签: vue.js vue-component vue-router


    【解决方案1】:

    正如 cmets 中提到的,第一个 async/await 解决方案有点误导,因为所有生命周期方法都是同步的。这是可行的,因为代码被转译为内部带有 IIFE 的同步函数。

    下面我添加了一些最近的sn-ps。

    旧答案

    用 async/await 试试。我删除了beforeRouteEnteraxios.spread 并添加了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);
        },
      },
    };
    

    更短

    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');
      },
    };
    

    更新答案

    您可以在生命周期方法中使用异步函数。

    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 和setup()

    在 Vue 3 中,您可以使用 async setup()。如果你使用它,你必须用Suspense 包装你的组件。警告!此 API 目前是实验性 https://v3.vuejs.org/guide/migration/suspense.html

    <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
        }
      }
    }
    

    【讨论】:

    • 函数 async created() 未运行
    • 奇怪。我在 5 分钟前测试过它。您的浏览器可能不支持 async/await 功能。使用 babeljs 进行编译。
    • vuejs 组件的所有生命周期事件都是同步的。它们不能是异步的,至少在 v2.6 之前是这样。
    【解决方案2】:

    您应该能够返回调用 axios.all 所返回的 Promise,例如:

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

    或者您可以向数据对象添加一个属性并使用它来显示加载器,直到所有 Promise 都已解决

    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);
            },           
        }
    };
    

    模板代码省略,但你可以根据isLoading切换你显示的内容。如果你沿着这条路线走,那么最好为加载器创建一个抽象。

    我还建议您可能想要查看 vuex,而不是将所有数据耦合到任何特定的组件状态。

    【讨论】:

      【解决方案3】:

      也许这可以帮助某人:

      试试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);
          }
      );
      

      【讨论】:

        猜你喜欢
        • 2019-08-01
        • 2019-04-28
        • 1970-01-01
        • 2019-02-08
        • 2022-01-24
        • 2021-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多