Skip to content

Instantly share code, notes, and snippets.

@js2me
Created November 3, 2022 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save js2me/9a8d69ec5b537b68ec66f0d3de85b139 to your computer and use it in GitHub Desktop.
Save js2me/9a8d69ec5b537b68ec66f0d3de85b139 to your computer and use it in GitHub Desktop.
use async effect
import { MutableRefObject, useEffect, useRef, useState } from "react";
type AsyncResult<T> = {
status: AsyncStatus;
data?: T;
error?: Error;
};
enum AsyncStatus {
Loading,
Success,
Failed
}
type AsyncOutput<T> = {
loading: boolean;
failed: boolean;
succeed: boolean;
data?: T;
error?: Error;
};
type AsyncEffectPayload = {
mountedRef: MutableRefObject<boolean>;
};
export const useAsyncEffect = <T>({
effect,
deps,
cleanup
}: {
effect: (payload: AsyncEffectPayload) => Promise<T>;
deps?: unknown[];
cleanup?: VoidFunction;
}): AsyncOutput<T> => {
const mountedRef = useRef(false);
const [asyncResult, setAsyncResult] = useState<null | AsyncResult<T>>(null);
useEffect(() => {
mountedRef.current = true;
setAsyncResult({ status: AsyncStatus.Loading });
effect({ mountedRef })
.then(data => {
if (!mountedRef.current) {
return;
}
setAsyncResult({ status: AsyncStatus.Success, data });
})
.catch(error => {
if (!mountedRef.current) {
return;
}
setAsyncResult({ status: AsyncStatus.Failed, error });
});
return () => {
mountedRef.current = false;
cleanup?.();
};
}, deps);
if (!asyncResult) {
return {
failed: false,
loading: true,
succeed: false
};
}
return {
failed: asyncResult.status === AsyncStatus.Failed,
loading: asyncResult.status === AsyncStatus.Loading,
succeed: asyncResult.status === AsyncStatus.Success,
error: asyncResult.error,
data: asyncResult.data
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment