【问题标题】:Vue pass axios response to a different methodVue将axios响应传递给不同的方法
【发布时间】:2020-05-11 20:24:03
【问题描述】:

我正在使用这种方法转换货币价值:

    converter (recipe_line) {
      axios.get('https://api.exchangeratesapi.io/latest?base=' + recipe_line.currency_buy + '&symbols=' + this.currentLocation.currency)
      .then(response => {
         let rate = response.data.rates[Object.keys(response.data.rates)[0]]
         return rate
      })
    },

这个方法在另一个方法中被调用:

recipeLineTotalConverted (recipe_line) {
  let pricebuy = this.converter(recipe_line)
}

在第一种方法中,如果我 console.log(rate) 结果是正确的。

但在第二种方法中,console.log(pricebuy) 返回 undefined。

第二种方法如何访问axios响应?

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:
    converter (recipe_line) {
          axios.get('https://api.exchangeratesapi.io/latest?base=' + recipe_line.currency_buy + '&symbols=' + this.currentLocation.currency)
          .then(response => {
             let rate = response.data.rates[Object.keys(response.data.rates)[0]]
             return rate
          })
        },
    

    最简单的方法是使用 async/await 语法来实现您想要做的事情,这种语法使您的代码更加同步,使其(在我看来)更具可读性。

      async converter(recipe_line) {
        try {
          const response = await axiox.get(
            'https://api.exchangeratesapi.io/latest?base=' +
              recipe_line.currency_buy +
              '&symbols=' +
              this.currentLocation.currency
          );
    
          return response.data.rates[Object.keys(response.data.rates)[0]];
        } catch (error) {
          console.log(error);
        }
      }
    

    它看起来像上面的样子,或者你可以调整它看起来像这样:

      converter(recipe_line) {
        axios
          .get(
            'https://api.exchangeratesapi.io/latest?base=' +
              recipe_line.currency_buy +
              '&symbols=' +
              this.currentLocation.currency
          )
          .then((response) => {
            let rate = response.data.rates[Object.keys(response.data.rates)[0]];
            Promise.resolve(rate);
          })
          .catch((err) => Promise.reject(err));
      }
    

    问题是,您实际上并没有从该承诺中返回任何东西,它需要解决,或者使用另一个承诺返回。

    return rate 没有解决这个承诺(尽管它可能应该),而是使用Promise.resolve() 来实现这一点。

    因此,尽管 Promise 确实解析了,但返回值并未解析为 .resolve() 未使用。

    从 ES6 开始,添加了 async/await 语法,使我们能够编写更同步样式的代码,尽管仍然是异步的,因为它是旧 Promise 语法 (.then/.catch) 的包装。

    还有,Object.keys(response.data.rates)有什么用,不能用键名来引用吗?

    例如,如果键是“rate1”,您将替换 response.data.rates['rate1']

    我不知道你的用例,所以这只是事后的想法。

    【讨论】:

    • 既然我有 .then 我认为承诺已经解决。您将 async 替换为 .then 但它们都返回相同的结果。
    • @Catmal 我想我可以更好地解释一下,promise 需要是 .resolve(d) 与您尝试返回的值(如果使用 Promise 语法),使用 async/ await return 选项将起作用,因为它将返回一个带有返回值的承诺,或者如果抛出一个错误则拒绝。因此,try/catch 块,而不是.catch。第一个版本解析为void,因为没有.resolve(d)。 Promise.resolve(returnValue).
    【解决方案2】:

    所以你的代码中有两处错误。

    1. 您没有从第一个方法返回任何内容。你必须回电到axios.get(/* ... */)
    2. 您正试图立即从异步操作中获取值。即使您从第一个方法返回值,您也只会得到 [object Promise] 而不是 undefined 作为值。

    解决此问题的最直接方法是使用async/await。但是,如果您尝试在视图中呈现此信息,您将需要一种或另一种方式的数据属性,因为 VueJS 无法直接在模板内等待异步操作。

    我稍微简化了您的示例以使用更简单的 API,但这是您可以实现此目的的一种方法:

    var app = new Vue({
      el: "#app",
      data: {
        url: ""
      },
      async mounted() {
        this.url = await this.getUrl();
      },
      methods: {
        getCat() {
          return axios
            .get("https://api.thecatapi.com/v1/images/search")
            .then((response) => {
              return response.data[0].url;
            });
        },
        async getUrl() {
          let catImage = await this.getCat();
          console.log(catImage); // you'll see this isn't undefined anymore
          return catImage;
        }
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <div id="app">{{ url }}</div>

    由于我们在这里使用async/await,因此您也可以在您的 axios 调用中放弃使用 Promise 并简化为:

        async getCat() {
          return (await axios("https://api.thecatapi.com/v1/images/search")).data[0].url;
        },
    

    更新

    您在 cmets 中提到您确实需要在模板中呈现此数据。我只是想明确一点,您要做的基本上是这样的:

    <div>{{ getUrl() }}</div>
    

    目前这在 VueJS 中是不可能的。将呈现到页面的只是[object Promise]。因为当你调用getUrl(一个异步函数)时,你首先会得到一个Promise。 Vue 不会更新异步函数的渲染结果。因此,当 Promise 解决(axios 返回结果)时,您仍然会在页面上看到 [object Promise]

    因此,您有两个选择。您可以更新您的 data 属性之一的值作为异步操作的副作用,或者您可以引入一个为您提供异步计算属性的库: https://github.com/foxbenjaminfox/vue-async-computed

    【讨论】:

    • 好的,现在我明白了为什么在第一个方法中正确打印了该值,但在第二个方法中却没有。在第二个中,它实际上返回 [object Promise]。问题是我使用 async.await 得到了相同的结果。关于在模板中显示它,我只使用 {{recipeLineTotalConverted (recipe_line)}}。我会继续努力的。。
    • 正是如此,我的意思是您不能在模板中使用该方法。您必须使用在承诺解决后更新的数据属性
    猜你喜欢
    • 2021-08-11
    • 2022-11-14
    • 1970-01-01
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2019-05-11
    相关资源
    最近更新 更多