[英]How do I prevent a race condition in a react hook?
我為 React 編寫了一個方便的鈎子,用於跟蹤 promise 是否正在運行、是否有錯誤以及結果如何。 它是這樣使用的:
const MyComponent = (props: IProps) => {
const [promise, setPromise} = useState<Promise | undefined>();
const {
hasRun,
isWaiting,
results,
error
} = useService(promise);
const doSomething = () => {
setPromise(runSomeAsyncCode());
};
return (
<div>...</div>
);
};
它只不過是隨着 promise 啟動、運行、成功或失敗而更新的一組狀態:
export const useService = <T>(promise?: Promise<T>) => {
const [hasRun, setHasRun] = useState<boolean>(false);
const [isWaiting, setIsWaiting] = useState<boolean>(false);
const [error, setError] = useState<Error | undefined>(undefined);
const [results, setResults] = useState<T | undefined>();
useEffect(() => {
if (!promise) {
return;
}
(async () => {
if (!hasRun) {
setHasRun(true);
}
setError(undefined);
setIsWaiting(true);
try {
const r = await promise;
setResults(r);
} catch (err) {
setResults(undefined);
setError(err);
} finally {
setIsWaiting(false);
}
})();
}, [promise]);
return {
error,
hasRun,
isWaiting,
results,
};
};
我的問題是,如果 promise 在之前的 promise 解決之前更新,那么之前的承諾的結果或錯誤仍將返回給組件。 例如,啟動幾個 AJAX 請求,其中第一個請求在一分鍾后失敗,但第二個請求在幾秒鍾內解決,導致初始成功,但在一分鍾后報告失敗。
如果 promise 在此期間發生了變化,我如何修改鈎子以便它不會因為錯誤或成功調用 setState?
為什么不跟蹤當前的promise
並在 promise 發生變化時放棄效果?
export const useService = <T>(promise?: Promise<T>) => {
const [hasRun, setHasRun] = useState<boolean>(false);
const [isWaiting, setIsWaiting] = useState<boolean>(false);
const [error, setError] = useState<Error | undefined>(undefined);
const [results, setResults] = useState<T | undefined>();
const promiseRef = useRef(promise);
promiseRef.current = promise; // ** keep ref always up to date
useEffect(() => {
if (!promise) {
return;
}
(async () => {
setHasRun(true);
setError(undefined);
setIsWaiting(true);
try {
const r = await promise;
if (promiseRef.current !== promise) {
return;
}
setResults(r);
setIsWaiting(false);
} catch (err) {
if (promiseRef.current !== promise) {
return;
}
setResults(undefined);
setError(err);
setIsWaiting(false);
}
})();
// you may want to reset states when the promise changes
return () => {
setHasRun(false);
setIsWaiting(false);
setError(undefined);
setResults(undefined);
}
}, [promise]);
return {
error,
hasRun,
isWaiting,
results,
};
};
正如文檔指出的那樣, useRef
不僅適用於 DOM 元素引用。
本質上,useRef 就像一個“盒子”,可以在其.current 屬性中保存一個可變值。 [...] 改變 .current 屬性不會導致重新渲染。
我在這里使用useRef
的原因是因為我們需要一個可變值,它可以保存最新的promise
參數而不會導致重新渲染。 因為promiseRef
永遠不會改變(只有.current
會改變),所以您可以使用**
分配最新的值並在異步 function 中訪問它,即使在時間過去並且組件已經重新渲染之后也是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.