簡體   English   中英

在 Vue.js 中等待 Ajax 響應數據

[英]Wait for Ajax response data in Vue.js

我有一個 Vue 組件,我試圖在其中使用 axios 從 API 獲取一些數據。

<template>
    <div>
        This is Default child component
        {{tools[0].name}}
    </div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
    tools: []
  },
  methods: {
      fetchData() {
        const customJs = new CustomJS();
        return customJs.getTools();
      }
  },
  created() {
    this.tools = this.fetchData(); //preferably need to wait here wait for response
  }
}
</script>

getTools()函數位於 Vue 組件文件之外的不同 JS 文件中,該文件使用 axios.get 進行 API 調用。

getTools(id = 0){
    this.apiTool += (id > 0) ? id : '';
    axios.get(this.apiTool, {
    })
    .then(function (response) {
        console.log(response.data);
        return response.data;
    })
    .catch(function (error) {
        console.log(error);
    });
}

問題是, {{tools}}未定義,因為getTools()需要一些時間來返回響應數據。 如何等待響應數據然后返回?

試試下面的代碼:這樣代碼只會在它實際加載時呈現

<div v-if="tools">
    This is Default child component
    {{tools[0].name}}
</div>

通常為此,我使用加載程序向用戶顯示請求正在進行中

<div v-if="loading">
  <loader /> //a loader component
</div>

<div v-else>
  // show the template since request finished
</div>

和腳本

export default {
  data: () => ({
    loading: false
  }),

  created() {
   this.loading = true
   axios.get('api') //your request
   .then(response => console.log(response))
   .finally(() => (this.loading = false)) //when the requests finish
  }

}

如果你不喜歡上面的方式,你可以使用beforeEnter這樣路由只會在請求完成時加載:

{
  path: '/my-route',
  component: YourComponent,
  props: true,
  beforeEnter (to, from, next) {
    axios.get('api-request')
     .then(response => {
      to.params.data = response //we pass data through props to the component
      next()
     })
  }
}
<template>
    <div v-if="isGetTools">
        This is Default child component
        {{tools[0].name}}
    </div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
    tools: []
  },
  data: function () {
    return {
      isGetTools: false
    }
  },
  methods: {
      fetchData() {
        const customJs = new CustomJS();
        this.tools = customJs.getTools();
        this.isGetTools = true;
      }
  },
  created() {
    this.fetchData(); //preferably need to wait here wait for response
  }
}
</script>

嘗試在您的 div 中添加 v-if。 並在從 AXIOS 獲取結果后將 isGetTools 更新為 true

您需要從您的請求中返回一個承諾

<template>
<div>
    This is Default child component
    {{tools[0].name}}
</div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
      tools: []
  },
  methods: {
      fetchData() {
         const customJs = new CustomJS();
         return new Promise((resolve, reject) => {
             customJs.getTools()
                 .then(res => resolve(res))
                 .catch(err => reject(err))
        })
     }
  },
  created() {
      this.fetchData().then(res => {
         this.tools = res);
      } //preferably need to wait here wait for response
    }
   }
 </script>

嘗試檢索已安裝的數據

    <template>
    // try adding this condition on div element.
                <div v-if="tools.length">
                    This is Default child component
                    {{tools[0].name}}
            </div>
        </template>

        <script>
        import { CustomJS } from '../js/custom.js';

        export default {
          name: 'HomeContent',
          props: {
            tools: []
          },
          methods: {
              fetchData() {
                const customJs = new CustomJS();
                return customJs.getTools();
              }
          },
          mounted: function () {
            this.tools = this.fetchData();    
            // or    
            // const customJs = new CustomJS();
            // this.tools =  customJs.getTools();
          }
        }
        </script>

您想要做的是將您的 getTools 函數定義為這樣的承諾:

getTools (id = 0) {
  return new Promise((resolve, reject) => {
    this.apiTool += (id > 0) ? id : '';
    axios.get(this.apiTool, {
    })
    .then(function (response) {
        console.log(response.data);
        resolve(response.data);
    })
    .catch(function (error) {
        console.log(error);
        reject(error)
    });
  })
}

然后你可以在你的組件代碼中使用它:

<template>
    <div>
        This is Default child component
        {{tools[0].name}}
    </div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
    tools: []
  },
  methods: {
      fetchData() {
        const customJs = new CustomJS();
          customJs.getTools().then((result) => {
            return result;
          }
        )

      }
  },
  created() {
    this.tools = this.fetchData(); //preferably need to wait here wait for response
  }
}
</script>

或者使用異步/等待:

<template>
    <div>
        This is Default child component
        {{tools[0].name}}
    </div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
    tools: []
  },
  methods: {
      async fetchData() {
      const customJs = new CustomJS();
      return await customJs.getTools()  
      }
  },
  created() {
    this.tools = this.fetchData(); //preferably need to wait here wait for response
  }
}
</script>

我不知道為什么這個問題會出現在我的“時間軸”中並且還沒有得到公認的答案,所以我還是會回答。 問題似乎在於對 OP 與 JS 中的異步代碼的理解。 這是修復(有 3 個)以使其更好:

<template>
    <div v-if="tools.length">
        {{tools[0].name}}
    </div> 
    <div v-else> // I. Use v-if/v-else to conditionally show data, in Vue 3 there will be another feature called "suspense" borned to do those things: https://vueschool.io/articles/vuejs-tutorials/suspense-new-feature-in-vue-3/
        This is Default child component
    </div>
</template>

<script>
import { CustomJS } from '../js/custom.js';

export default {
  name: 'HomeContent',
  props: {
    tools: []
  },
  methods: {
    async fetchData() {
      const customJs = new CustomJS();
      this.tools = await customJs.getTools(); 
      // II. The OP assigned a promise to this.tools, this.tools wasn't being assigned to any actual data at all, because: 
      // 1. getTools() didn't return any data
      // 2. even if it returned data, it wasn't being promise-resolved (by await/then) before assigned to this.tools
    }
  },
  created() {
    this.fetchData();
  }
}
</script>

async getTools(id = 0){
  this.apiTool += (id > 0) ? id : '';

  try {
    const response = await axios.get(this.apiTool, {});
    console.log(response.data);
    return response.data; 
    // III. The OP didn't return any fetched data at all, it just called API then do nothing. All the returns were returned in the arrow functions, the actual function getTools didn't get any return

  }
  catch (err) {
    console.log(err)
  }
},

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM