问题描述:
点击A、B、C,如果操作过快,会出现虽然点击了C,但是上面显示的是B的信息。

image.png
解决方案
每轮渲染的 Effect 都有其独立的 ignore 变量。最初,ignore 变量被设置为 false。但如果一个 Effect 被清理(例如,当你选择不同的人时),它的 ignore 变量会变为 true。因此,请求完成的顺序已经不再重要。只有最后选中的 Effect 的 ignore 变量会是 false,因此它将会调用 setData(result)。而之前的 Effect 已经被清理,所以 if (!ignore) 的检查会阻止它们调用 setData:
const DELAY_MIL_SEC = [2000, 3000, 1000];
const ID_LABEL = ['A', 'B', 'C'];
export default function Demo() {
const [activeIndex, setActiveIndex] = useState<number>(0);
const [data, setData] = useState({ id: '', timestamp: '', back: '' });
// 在这里添加状态量,只会显示最先点击的结果,最后点击的结果不会显示。
// 理想的情况是显示最后点击的结果,而不是最先点击的结果。
const onClick = (id: number) => {
if (refReq.current) return; // 信号量存在
refReq.current = true;
api.user
.delayFn({ id, delay: DELAY_MIL_SEC[id] })
.then((response) => {
refReq.current = false;
setData({ ...response });
})
.catch((err) => {
console.error('err', err);
});
};
useEffect(() => {
let ignore = false;
setData({ id: '', timestamp: '', back: '' });
api.user
.delayFn({ id: activeIndex, delay: DELAY_MIL_SEC[activeIndex] })
.then((response) => {
if (!ignore) {
setData({ ...response });
}
})
.catch((err) => {
console.error('err', err);
});
return () => {
ignore = true;
};
}, [activeIndex]);
return (
<div className={styles.App}>
<header className={styles.AppHeader}>
<h2>解决api请求返回顺序紊乱的问题</h2>
<div>
{data?.id.toString() && (
<p>
<span>{ID_LABEL[data.id]}</span>
<span>{data.timestamp}</span>
<span>{data.back}</span>
</p>
)}
{ID_LABEL.map((label: string, index: number) => (
// eslint-disable-next-line react/button-has-type
<button
key={label}
onClick={() => {
// onClick(index);
setActiveIndex(index);
}}
>
{`${ID_LABEL[index]}-${DELAY_MIL_SEC[index].toString().substring(0, 1)}sec`}
</button>
))}
</div>
<div style={{ height: '600px' }}> </div>
</header>
</div>
);
}