在无限加载器和过滤器上重复条目



我正在使用vue-infinite-loader来显示用户并在滚动上加载它们。另外,我有一个按名称的过滤器。

我遵照https://peachscript.github.io/vue-infinite-loading/guide/use-with-filter-or-tabs.html

给出的说明下面是过滤器的HTML:
<input v-model="name" type="text" class="form-control" placeholder="Search by name" @input="changeName">

这里是相关的值方法:

methods: {
infiniteHandler: function ($state) {
console.log(api + this.parameter);
axios.get(api + this.parameter, {params: {page: this.page}}).then((result) =>   {
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page += 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
},
changeName() {
this.parameter= '?name=' + encodeURIComponent(this.name);
this.page = 1;
this.users = [];
this.infiniteId += 1;                          
},

如果我输入now "Max"作为输入文本域中的用户名,则changeName执行3次,MMaMax分别执行一次。问题是,调用是并行的,这意味着从Max开始的用户也将匹配从MaM开始的用户。因此,我突然有了重复的用户,他们的名字不是以Max开头,而是以Marjon开头,等等。

我实际上在changeName()内部有一个超时,以防止每次击键时HTTP调用:

changeName() {            
clearTimeout(this.timeout);
this.timeout = setTimeout(function() { ...}, 200);
},

然而,上面的理论问题仍然可能发生在这里(如果按键和HTTPS调用都需要超过200ms)。

如果用户输入"然后是&;Max"axios调用由"Ma"被停止,并立即调用"Max"执行。

要取消axios请求,可以使用canceltoken

请注意,当调用infiniteHandler时,以前的请求是如何被取消的,并且当请求完成时取消令牌将被删除

因此,除了这里的几行代码外,不需要额外的代码
methods: {
infiniteHandler: function ($state) {
console.log(api + this.parameter);
// _cancelSource is truthy if there's a request "in flight"
if (this._cancelSource) {
this._cancelSource.cancel('new search');
this._cancelSource = null;
}
// get a new canceToken
this._cancelSource = axios.CancelToken.source();
axios.get(api + this.parameter, {
cancelToken: this._cancelSource.token
params: {page: this.page}
}).then((result) =>   {
// no need to cancel now
this._cancelSource = null;
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page += 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
},

如果取消不完全工作-您可以链接axios返回的承诺

然而,我不认为这是必需的

如果您不想通过删除cancelToken代码 来取消之前的请求(出于其他目的),可能仍然有用。

methods: {
infiniteHandler: function ($state) {
console.log(api + this.parameter);

// initialise the promise for first time
this._requestPromise = this._requestPromise || Promise.resolve();

// _cancelSource is truthy if there's a request "in flight"
if (this._cancelSource) {
this._cancelSource.cancel('new search');
this._cancelSource = null;
}
// get a new canceToken
this._cancelSource = axios.CancelToken.source();

// chain on to the previous request
// NOTE: cancelling the previous request will make it reject ... 
//      but that can be handled
this._requestPromise = this._requestPromise
// handle any cancelled previous request
// or previous request rejections
// we still want to do this one if the previous rejected
.catch(() => {}) 
.then(() => {
axios.get(api + this.parameter, {
cancelToken: this._cancelSource.token
params: {page: this.page}
}).then((result) =>   {
// no need to cancel now
this._cancelSource = null;
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page += 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});
});
},

您可以使用axios的CancelToken在另一个axios请求开始之前取消axios请求

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get(api + this.parameter, {
params: {page: this.page}},
cancelToken: source.token
).then((result) =>   {
if (result.data.meta.current_page <= result.data.meta.last_page) {
this.page += 1;
this.users.push(...result.data.data);
$state.loaded();
} else {
$state.complete();
}
});

(代码未测试,但给出了想法)

最新更新