useMemoSingleThreaded.tsx 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. import { useEffect, useRef, useState } from "react";
  2. export default function useMemoSingleThreaded<T>(
  3. fn: () => T | Promise<T>,
  4. deps: any[],
  5. ): T {
  6. const [result, setResult] = useState<T>(null);
  7. const updateInProgress = useRef(false);
  8. const updateRequired = useRef(false);
  9. useEffect(() => {
  10. const main = async () => {
  11. if (updateInProgress.current) {
  12. updateRequired.current = true;
  13. return;
  14. }
  15. updateInProgress.current = true;
  16. const result = fn();
  17. if (isPromise(result)) {
  18. const resultValue = await result;
  19. setResult(resultValue);
  20. } else {
  21. setResult(result);
  22. }
  23. updateInProgress.current = false;
  24. if (updateRequired.current) {
  25. updateRequired.current = false;
  26. setTimeout(main, 0);
  27. }
  28. };
  29. main();
  30. }, deps);
  31. return result;
  32. }
  33. function isPromise<T>(obj: T | Promise<T>): obj is Promise<T> {
  34. return obj && typeof (obj as any).then === "function";
  35. }