所有人的美好一天,
我正在做一个React课程,并且已经将代码提交给了审阅者。他给我发了几条评论,有一条我无法解决。
评论如下:
检查(query === this.state.query)以确保您不会将内容替换为旧的响应
部分代码如下:
updateQuery = (query) => {
this.setState({
query: query
})
this.updateWantedBooks(query);
}
updateWantedBooks = (query) => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
if (wantedBooks.error) {
this.setState({ wantedBooks: [] });
} else {
this.setState({ wantedBooks: wantedBooks });
}
})
} else {
this.setState({ wantedBooks: [] });
}
}
任何人都可以帮助我我该怎么办?
致谢。
答案 0 :(得分:2)
代码审查者是正确的,如果用户输入了相同的查询,您真的不想替换响应。
您必须将用户最近搜索过的内容存储在某个地方:
this.setState({ wantedBooks: [], query });
如果成功响应:
this.setState({ wantedBooks, query });
然后在进行进一步搜索时进行检查:
if (query && query !== this.state.query) {
// continue the search only if query is different that current
答案 1 :(得分:1)
您可以使用工厂函数来更安全地诱捕成员,而不是依赖于其他代码容易滥用的外部成员。
您已经发现,诱捕和测试query == this.state.query
可以正常工作,但可以说不是最佳的解决方案。
稍加思考,您就可以自动强制updateWantedBooks()
的每次调用拒绝同一功能(如果尚未解决)返回的上一个承诺,从而使任何成功链接到上一个承诺的回调不会触发其错误路径。
这可以通过可重复使用的canceller
实用程序来实现,该实用程序接受两个回调并利用Promise.race(),如下所示:
// reusable cancellation factory utility
function canceller(work, successCallback) {
var cancel;
return async function(...args) {
if (cancel) {
cancel(new Error('cancelled')); // cancel previous
}
return Promise.race([
work(...args),
new Promise((_, reject) => { cancel = reject }) // rejectable promise
]).then(successCallback);
};
};
这是一个演示...
// reusable cancellation factory utility
function canceller(work, successCallback) {
var cancel;
return async function(...args) {
if (cancel) {
cancel(new Error('cancelled')); // cancel previous
}
return Promise.race([
work(...args),
new Promise((_, reject) => { cancel = reject })
]).then(successCallback);
};
};
// delay utility representing an asynchronous process
function delay(ms, val) {
return new Promise(resolve => {
setTimeout(resolve, ms, val);
});
};
function MySpace() {
// establish a canceller method with two callbacks
this.updateWantedBooks = canceller(
// work callback
async (query) => delay(500, query || { 'error': true }), // a contrived piece of work standing in for BooksAPI.search()
// success callback
(wantedBooks => this.setState(wantedBooks)) // this will execute only if work() wins the race against cancellation
);
this.setState = function(val) {
console.log('setState', val);
return val;
};
};
var mySpace = new MySpace();
mySpace.updateWantedBooks({'value':'XXX'}).then(result1 => { console.log('result', result1) }).catch(error => { console.log(error.message) }); // 'cancelled'
mySpace.updateWantedBooks(null).then(result2 => { console.log('result', result2) }).catch(error => { console.log(error.message) }); // 'cancelled'
mySpace.updateWantedBooks({'value':'ZZZ'}).then(result3 => { console.log('result', result3) }).catch(error => { console.log(error.message) }); // {'value':'ZZZ'} (unless something unexpected happened)
请注意,canceller()
不会尝试中止它启动的异步过程,而是会阻碍返回的Promise的成功路径,而倾向于错误路径。
答案 2 :(得分:0)
我认为审阅者的观点是Search API的响应是异步的,并且在用户改变主意并已请求搜索“ query 2”之后,“ query 1”的结果才能到达。因此,当响应到达时-我们需要检查我们是否真的对此感兴趣:
updateQuery = query => {
this.setState({
query: query
wantedBooks: []
})
this.updateWantedBooks(query);
}
updateWantedBooks = query => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
// if updateQuery("query1) and updateQuery("query2") called in a row
// then response for query1 can arrive after we requested query2
// => for some period of time we'll show incorrect search results
// so adding check if query still the same can help
if (query !== this.state.query) {
// outdated response
return;
} else if (wantedBooks.error) {
// query is okay, but server error in response
this.setState({
wantedBooks: []
})
} else {
// success response to requested query
this.setState({ wantedBooks });
}
})
}
}
答案 3 :(得分:0)
伙计们,我用您的答案做了一些测试,但是我意识到代码在某种程度上表现得很奇怪。
因此,我在审阅者评论的其他部分中看到了我以前没有看过的部分,在这里做我的回答,即以下评论:
在promise的'then'部分中检查if(query === this.state.query),以确保您不会将内容替换为旧的响应。
这个“内在”然后在我的大脑中跳动。
所以,我想我已经达到了令人满意的代码;当然,也许这不是确定的解决方案,这就是为什么我要在这里展示给您,并在需要改进的地方随时发表评论。我在下面放了代码:
updateQuery = (query) => {
this.setState({
query: query
})
this.updateWantedBooks(query);
}
updateWantedBooks = (query) => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
if (wantedBooks.error) {
this.setState({ wantedBooks: [] });
} else if (query !== this.state.query) {
this.setState( { wantedBooks: [] });
} else {
this.setState({ wantedBooks: wantedBooks });
}
})
} else {
this.setState({ wantedBooks: [] });
}
}
致谢