useEffectSingleThreaded.tsx 1.1 KB

123456789101112131415161718192021222324252627282930313233
  1. import { useEffect, useRef } from 'react';
  2. import { isPromise } from '../utils';
  3. // useEffectSingleThreaded is a useEffect that will only run one at a time, and will
  4. // caches the latest deps of requests that come in while it is running, and will
  5. // run that after the current run is complete.
  6. export default function useEffectSingleThreaded(
  7. fn: (deps) => void | Promise<void>,
  8. deps: any[]
  9. ): void {
  10. const updateInProgress = useRef(false);
  11. const nextRequestDepsRef = useRef<any[]>(null);
  12. useEffect(() => {
  13. const main = async (deps) => {
  14. if (updateInProgress.current) {
  15. nextRequestDepsRef.current = deps;
  16. return;
  17. }
  18. updateInProgress.current = true;
  19. const result = fn(deps);
  20. if (isPromise(result)) {
  21. await result;
  22. }
  23. updateInProgress.current = false;
  24. if (nextRequestDepsRef.current) {
  25. const deps = nextRequestDepsRef.current;
  26. nextRequestDepsRef.current = null;
  27. setTimeout(() => main(deps), 0);
  28. }
  29. };
  30. main(deps);
  31. }, deps);
  32. }