我已经为React写了一个方便钩子,用于跟踪一个承诺是否正在运行,是否存在错误以及结果是什么。这样使用:
# desired output:
tensor([ -5.0000, -100.0000, -1.0000, 0.1000, 7.0000, 100.0000])
只不过是随着承诺开始,运行,成功或失败而更新的一组状态:
const MyComponent = (props: IProps) => {
const [promise, setPromise} = useState<Promise | undefined>();
const {
hasRun,
isWaiting,
results,
error
} = useService(promise);
const doSomething = () => {
setPromise(runSomeAsyncCode());
};
return (
<div>...</div>
);
};
我的问题是,如果承诺在先前的承诺解决之前更新,那么先前的承诺的结果或错误仍将返回给组件。例如,启动几个AJAX请求,第一个请求在一分钟后失败,但是第二个请求在几秒钟内解决,则导致最初成功,但是一分钟后又报告失败。
如果在此期间更改了承诺,如何修改挂钩,以使其不会调用setState来获取错误或成功?
答案 0 :(得分:1)
为什么不跟踪当前的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,
};
};
正如docs所指出的, useRef
不仅仅用于DOM元素引用。
从本质上讲,useRef就像一个“盒子”,可以在其.current属性中保留一个可变值。 [...]更改.current属性不会导致重新渲染。
我在这里使用useRef
的原因是因为我们需要一个可变的值,该值可以容纳最新的promise
参数而不会引起重新渲染。由于promiseRef
永不更改(仅.current
会更改),因此您可以在**
的行上分配最新值,并在异步函数中访问它,即使时间已经过去并且组件已经重新呈现。