fix(marketplace): stale detail response guard (pr_agent #444 round 3)
跟 round 2 同类 race condition:openDetail 用户快速点两张卡片时,先点 A 的 detail response 可能晚于 B 到达 → 覆盖 B 的 detail / Install / Like 作用错对象。 修:复用 useRef seq token 模式,detailSeqRef 单调递增,response 比较 seq 丢 弃 stale。逻辑跟 refresh() 完全对称。
This commit is contained in:
1 parent
4af7fec82f
commit
9e119e2a2f
1 file changed
+6
-2
@@ -53,9 +53,10 @@ export function Marketplace() {
|
||||
return () => window.clearTimeout(id);
|
||||
}, [query]);
|
||||
|
||||
// 单调递增 seq 防 stale 响应覆盖:用户快速改 query 时旧请求的 response
|
||||
// 单调递增 seq 防 stale 响应覆盖:用户快速改 query / 切换 pack 时旧请求 response
|
||||
// 可能晚于新请求到达,比较 seq 丢弃过期结果。
|
||||
const reqSeqRef = useRef(0);
|
||||
const detailSeqRef = useRef(0);
|
||||
const refresh = useCallback(async () => {
|
||||
const seq = ++reqSeqRef.current;
|
||||
setLoading(true);
|
||||
@@ -78,18 +79,21 @@ export function Marketplace() {
|
||||
}, [refresh]);
|
||||
|
||||
const openDetail = async (id: string) => {
|
||||
const seq = ++detailSeqRef.current;
|
||||
setSelectedId(id);
|
||||
setDetail(null);
|
||||
setDetailLoading(true);
|
||||
try {
|
||||
const d = await fetchMarketplaceDetail(id);
|
||||
if (seq !== detailSeqRef.current) return; // stale: 用户已切到另一个 pack
|
||||
setDetail(d);
|
||||
} catch (error) {
|
||||
if (seq !== detailSeqRef.current) return;
|
||||
console.error('[marketplace] detail failed', error);
|
||||
setActionMsg({ kind: 'err', text: t('marketplace.errors.detail', { err: errorMessage(error) }) });
|
||||
setSelectedId(null);
|
||||
} finally {
|
||||
setDetailLoading(false);
|
||||
if (seq === detailSeqRef.current) setDetailLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user