Skip to main content

useBlockMultipleAsyncCalls

진행 중인 비동기 호출이 있을 때 중복 호출을 방지하며, isLoadingisError 상태를 함께 제공하는 커스텀 훅입니다.

debounce/throttle는 함수의 중복 호출을 방지하는 데 대부분의 경우에 효과적입니다. 하지만, debounce/throttle는 비동기 작업의 완료를 보장하지 않기 때문에 다음과 같은 한계가 있습니다:

  1. debounce/throttle 시간이 API 응답 시간보다 짧을 경우: 비동기 작업이 완료되지 않은 상태에서 다시 호출될 수 있습니다.
  2. debounce/throttle 시간이 API 응답 시간보다 길 경우: 비동기 작업이 완료되었지만 버튼과 같은 요소가 여전히 비활성화되어 있을 수 있습니다.
  3. 즉각적인 반응을 원하는 경우: debounce/throttle는 호출을 지연시키기 때문에 사용자에게 즉각적인 반응을 보여주기에 제한적입니다.
  4. debounce/throttle시간을 기반으로 동작하기 때문에 얼마나 자주 실행되는지가 중요하지 중복 호출 여부를 파악하기 어렵습니다.

위와 같은 한계점을 대응하고자 한다면 useBlockMultipleAsyncCalls를 사용할 수 있습니다.


Code

🔗 실제 구현 코드 확인


Interface

typescript
interface UseBlockMultipleAsyncCallsReturnType {
isError: boolean;
isLoading: boolean;
blockMultipleAsyncCalls: <T, Args extends unknown[]>(
callback: (...args: Args) => Promise<T>
) => (...args: Args) => Promise<T | undefined>;
}
typescript
function useBlockMultipleAsyncCalls(): UseBlockMultipleAsyncCallsReturnType

Usage

기본 사용법

blockMultipleAsyncCalls(callback)은 래핑된 비동기 함수를 반환합니다. 반환된 함수를 이벤트 핸들러로 직접 사용할 수 있습니다.

typescript
import { useBlockMultipleAsyncCalls } from '@modern-kit/react';

const Component = () => {
const { isLoading, isError, blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();

const fetchData = async () => {
const data = await fetch('/api/data').then((res) => res.json());
// 데이터 처리
};

const handleClick = blockMultipleAsyncCalls(fetchData);

return (
<div>
<button onClick={handleClick} disabled={isLoading}>
{isLoading ? '로딩 중...' : '데이터 불러오기'}
</button>
{isError && <p>에러가 발생했습니다.</p>}
</div>
);
};

인자 전달

콜백 함수에 인자를 전달할 수 있습니다.

typescript
import { useBlockMultipleAsyncCalls } from '@modern-kit/react';

const Component = () => {
const { isLoading, blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();

const fetchUser = async (userId: number) => {
const user = await fetch(`/api/users/${userId}`).then((res) => res.json());
// 사용자 정보 처리
};

return (
<button onClick={() => blockMultipleAsyncCalls(fetchUser)(42)} disabled={isLoading}>
사용자 불러오기
</button>
);
};

@tanstack/react-query와 함께 사용하기

typescript
import { useBlockMultipleAsyncCalls } from '@modern-kit/react';
import { useQuery } from '@tanstack/react-query';

const Component = () => {
const { blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();

const fetchUser = async ({ id }: { id: number }) => {
const user = await fetch(`/api/users/${id}`).then((res) => res.json());
return user;
};

const mutation = useMutation({
mutationFn: blockMultipleAsyncCalls(fetchUser),
});

return <button onClick={() => mutation.mutate({ id: 42 })}>사용자 불러오기</button>;
};

Example

Example1 (기본 사용 예제)

버튼을 빠르게 여러 번 클릭해보세요. isLoadingtrue인 동안에는 중복 요청이 차단되며, 버튼이 비활성화됩니다.

버튼을 빠르게 여러 번 클릭해도 진행 중인 요청이 완료되기 전까지 한 번만 실행됩니다.

버튼 클릭 횟수
0
실제 API 호출 횟수
0

Example2 (isError 처리 예제)

에러가 발생하면 isErrortrue로 변경되고, 다음 정상 호출 시 false로 초기화됩니다.

isLoading: false
isError: false

버튼을 클릭하면 로그가 표시됩니다.