1. 问题描述
在上述图片中,由于本项目不同 tab 使用的同一个 redux store,所以每次切换 tab 时,如果在当前 tab 中请求的数据时间比较长,在此期间,又切换到另外一个标签页,那么这种情况上一次请求获取的数据就展示在当前页面
2. 解决方案
2.1 根据时间戳判断两次请求是否为同一次请求
effecs: {
async query() {
const currentTimeStamp = new Date().getTime()
sessionStorage.setItem('appViewTimeStamp', currentTimeStamp)
let res = await requestAPI()
const sessionTimeStamp = sessionStorage.getItem('appViewTimeStamp')
if (Number(sessionTimeStamp) === currentTimeStamp) {
this.save({ data: res.data })
}
}
}
2.2 撤回请求
2.2.1 AbortController
import React, { useEffect, useState } from 'react';
const FetchDataComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
// 创建一个 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 发起网络请求
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.then(data => setData(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
} else {
console.error('请求失败', error);
}
});
// 在组件卸载时执行清理函数
return () => {
controller.abort(); // 取消请求
};
}, []); // 空依赖数组表示只在挂载和卸载时运行
return (
<div>
{data ? (
<div>{JSON.stringify(data)}</div>
) : (
<div>加载中...</div>
)}
</div>
);
};
export default FetchDataComponent;
2.2.2 Axios Cancel Token
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const FetchDataComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
const source = axios.CancelToken.source();
// 发起网络请求
axios.get('https://api.example.com/data', {
cancelToken: source.token,
})
.then(response => setData(response.data))
.catch(error => {
if (axios.isCancel(error)) {
console.log('请求被取消');
} else {
console.error('请求失败', error);
}
});
// 在组件卸载时执行清理函数
return () => {
source.cancel('组件卸载,请求取消');
};
}, []);
return (
<div>
{data ? (
<div>{JSON.stringify(data)}</div>
) : (
<div>加载中...</div>
)}
</div>
);
};
export default FetchDataComponent;
2.3 使用第三方库(如 react-query 或 swr)
这样的库内置了管理请求状态和缓存的功能,并且可以更容易地处理请求取消和组件卸载等场景。
import React from 'react';
import { useQuery } from 'react-query';
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('网络响应错误');
}
return response.json();
};
const FetchDataComponent = () => {
const { data, error, isLoading } = useQuery('fetchData', fetchData, {
staleTime: 5000, // 5 秒内数据保持新鲜
});
if (isLoading) return <div>加载中...</div>;
if (error) return <div>请求失败: {error.message}</div>;
return (
<div>
{data && <div>{JSON.stringify(data)}</div>}
</div>
);
};
export default FetchDataComponent;