ente/web/packages/shared/hooks/useMemoSingleThreaded.tsx
2024-03-01 12:21:07 +05:30

39 lines
1.1 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
export default function useMemoSingleThreaded<T>(
fn: () => T | Promise<T>,
deps: any[],
): T {
const [result, setResult] = useState<T>(null);
const updateInProgress = useRef(false);
const updateRequired = useRef(false);
useEffect(() => {
const main = async () => {
if (updateInProgress.current) {
updateRequired.current = true;
return;
}
updateInProgress.current = true;
const result = fn();
if (isPromise(result)) {
const resultValue = await result;
setResult(resultValue);
} else {
setResult(result);
}
updateInProgress.current = false;
if (updateRequired.current) {
updateRequired.current = false;
setTimeout(main, 0);
}
};
main();
}, deps);
return result;
}
function isPromise<T>(obj: T | Promise<T>): obj is Promise<T> {
return obj && typeof (obj as any).then === "function";
}