javascript - 以与搜索功能请求相同的顺序获取 axios 响应
问题描述
我目前正在使用 axios 在 React Native 中开发搜索功能。
在实现搜索功能时,我使用 lodash 的 debounce 来限制发送的请求数量。
但是,由于不是以相同的顺序接收请求响应,因此可能会显示不正确的搜索结果。
例如,当用户在输入字段中输入“家居装饰”时,将有两个请求。
一个带有“Home”的请求,下一个带有“Home deco”作为搜索查询文本的请求。
如果带有“Home”的请求比第二个请求需要更多的时间来返回,我们最终将显示“Home”查询文本而不是“Home deco”的结果
如果响应按顺序返回,但如果在“Home deco”请求之后返回“Home ”请求,则应按顺序向用户显示这两个结果,则应忽略“Home”响应。
以下是示例代码
function Search (){
const [results, setResults] = useState([]);
const [searchText, setSearchText] = useState('');
useEffect(() => {
getSearchResultsDebounce(searchText);
}, [searchText]);
const getSearchResultsDebounce = useCallback(
_.debounce(searchText => {
getSearchResults(searchText)
}, 1000),
[]
);
function getSearchResults(searchText) {
const urlWithParams = getUrlWithParams(url, searchText);
axios.get(urlWithParams, { headers: config.headers })
.then(response => {
if (response.status === 200 && response.data)
{
setResults(response.data);
} else{
//Handle error
}
})
.catch(error => {
//Handle error
});
}
return (
<View>
<SearchComponent onTextChange={setSearchText}/>
<SearchResults results={results}/>
</View>
)
}
解决上述问题的最佳方法是什么?
解决方案
如果您想避免使用外部库来减小包大小,例如axios-hooks,我认为您最好使用 axios 中包含的 CancelToken 功能。
正确使用 CancelToken 功能还将防止任何警告对未能取消异步任务做出反应。
Axios 有一个很好的页面来解释如何在这里使用 CancelToken 功能。如果您想更好地了解它的工作原理以及它为何有用,我建议您阅读。
以下是我将如何在您提供的示例中实现 CancelToken 功能:
OP 在回复中澄清说他们不想实现取消功能,在这种情况下,我会使用如下时间戳系统:
function Search () {
//change results to be a object with 2 properties, timestamp and value, timestamp being the time the request was issued, and value the most recent results
const [results, setResults] = useState({
timeStamp: 0,
value: [],
});
const [searchText, setSearchText] = useState('');
//create a ref which will be used to store the cancel token
const cancelToken = useRef();
//create a setSearchTextDebounced callback to debounce the search query
const setSearchTextDebounced = useCallback(
_.debounce((text) => {
setSearchText(text)
), [setSearchText]
);
//put the request inside of a useEffect hook with searchText as a dep
useEffect(() => {
//generate a timestamp at the time the request will be made
const requestTimeStamp = new Date().valueOf();
//create a new cancel token for this request, and store it inside the cancelToken ref
cancelToken.current = CancelToken.source();
//make the request
const urlWithParams = getUrlWithParams(url, searchText);
axios.get(urlWithParams, {
headers: config.headers,
//provide the cancel token in the axios request config
cancelToken: source.token
}).then(response => {
if (response.status === 200 && response.data) {
//when updating the results compare time stamps to check if this request's data is too old
setResults(currentState => {
//check if the currentState's timeStamp is newer, if so then dont update the state
if (currentState.timeStamp > requestTimeStamp) return currentState;
//if it is older then update the state
return {
timeStamp: requestTimeStamp,
value: request.data,
};
});
} else{
//Handle error
}
}).catch(error => {
//Handle error
});
//add a cleanup function which will cancel requests when the component unmounts
return () => {
if (cancelToken.current) cancelToken.current.cancel("Component Unmounted!");
};
}, [searchText]);
return (
<View>
{/* Use the setSearchTextDebounced function here instead of setSearchText. */}
<SearchComponent onTextChange={setSearchTextDebounced}/>
<SearchResults results={results.value}/>
</View>
);
}
如您所见,我还更改了搜索本身的去抖方式。我在 searchText 值本身去抖动的地方更改了它,并且当 searchText 值更改时运行带有搜索请求的 useEffect 挂钩。这样我们可以取消先前的请求,运行新的请求,并在同一个钩子中卸载时进行清理。
我修改了我的响应以希望实现 OP 想要发生的事情,同时还包括在组件卸载时正确取消响应。
推荐阅读
- vuejs3 - Vue 3 中的自定义指令
- powerbi - Power BI:填补两个日期之间的空白,排除超出范围的日期
- github - GitHub 检查更改它在 Azure DevOps 中构建的存储库
- openstack - 从先前的命令输出重新创建 openstack 工件?
- r - 如何标记散点图上对角线以下的所有点
- pandas - 获取 TypeError:稀疏矩阵长度不明确;在进行多类分类时使用 getnnz() 或 shape[0]
- python - 选项菜单对齐问题 tkinter
- azure-devops - 在 azure devops 中维护构建和部署历史
- java - Spring:@RequestBody 和 JSON 的错误 400
- python - 尝试使用延迟的 dask 读取和计算 csv 文件中的行数