正确设置 Vue.js 方法来处理 Axios 异步请求



我有Vue.js应用程序,它使用Axios从API获取一些复杂的数据,然后可视化这些数据。 我的代码如下所示:

{
data: () => ({
data: null,  // or Object, it doesn't matter now
loading: false,
errored: false,
loadingMessage: ''
}),
methods: {
loadData: function() {
this.loading = true;
this.loadingMessage = 'Fetching Data';
axios.get('api/url/').then((response) => {
this.data= response.data;  // or this.$set(this, 'data', response.data), it doesn't matter now
this.loadingMessage = 'Process Data';
this.processData();
})
.catch(function () {
this.errored= true;
})
.then(function () {
this.loading = false;
})
},
processData: function() {
// process data
}
}
}

然后我点击模板中的按钮,这个按钮调用loadData()函数。 它工作正常,但是获取数据需要一些时间,处理也需要一些时间,Vue 仅在 axios 请求完成后更改模板和变量。所以我只看到Fetching Data消息,但没有看到Process Data.

如何向用户显示现在处理数据的哪个阶段? 也许我应该在watch methods中调用processData()函数,但这对我来说似乎有点过分了。

更新

我最终得到了setTimeout()包装。请参阅下面的答案。

Vue 有一个名为nextTick的函数,这是一个异步函数,基本上意味着"在下一次视觉更新后执行以下代码"。如果我有这样的视觉更新,我通常会使用此方法。

我认为您的示例中的代码如下所示:

axios
.get('api/url/')
.then((response) => {
this.data= response.data;
this.loadingMessage = 'Process Data';
return this.$nextTick();
})
.then(() => {
this.processData();
})
.catch (etc ...  

我不完全确定。我通常在支持 webpack/babel 的环境中工作,在这种情况下,我只会让整个函数async并编写:

async function fn() {
const response = await axios.get('api/url/');
this.data = response.data;
this.loadingMessage = 'Process Data';
await this.$nextTick();
this.processData();
}

你可以在这里阅读它(https://v2.vuejs.org/v2/guide/reactivity.html#Async-Update-Queue(

您可以尝试按如下方式更改函数吗:

loadData: function() {
this.loading = true;
this.loadingMessage = 'Fetching Data';
axios.get('api/url/').then((response) => {
this.data= response.data;  // or this.$set(this, 'data', response.data), it doesn't matter now
this.$nextTick(() => {
this.loadingMessage = 'Process Data';
this.processData();
})
})
.catch(function () {
this.errored= true;
})
.then(function () {
this.loading = false;
})
},

我尝试使用$nextTick(),正如@joachim-bøggild建议的那样。我甚至试图用$forceUpdate()来拱起这个目标。但由于某种我不清楚的原因,我没有观察到我需要的效果。控制台显示值已更改。但是在屏幕和 Vue Devtools 中,旧结果会显示,直到请求完成。

所以我决定用一个例子来补充这个问题,并开始在 JsFiddle 上创建演示。为了显示我需要的渲染延迟,我使用了setTimeout(() =>{ this.loading = false}, 1000),完全没有问题。

我将这种方法移植到我的代码中,一切都运行良好。直到我试图删除这个setTimeout().问题又出现了。

因此,最终,我最终选择了这个代码设计:

...
axios.get('api/url/').then((response) => {
this.data= response.data;
this.loadingMessage = 'Process Data';
setTimeout(() => {
this.processData();
this.loading = false;
}, 10);  // if this value less than 10 error still occurs
})
.catch(function () {
this.errored= true;
})
...

如果有人了解为什么会发生这种行为,请完成我的回答。

最新更新