useBlockMultipleAsyncCalls
진행 중인 비동기 호출이 있을 때 중복 호출을 방지하며, isLoading과 isError 상태를 함께 제공하는 커스텀 훅입니다.
debounce/throttle는 함수의 중복 호출을 방지하는 데 대부분의 경우에 효과적입니다.
하지만, debounce/throttle는 비동기 작업의 완료를 보장하지 않기 때문에 다음과 같은 한계가 있습니다:
debounce/throttle시간이 API 응답 시간보다 짧을 경우: 비동기 작업이 완료되지 않은 상태에서다시 호출될 수 있습니다.debounce/throttle시간이 API 응답 시간보다 길 경우: 비동기 작업이 완료되었지만버튼과 같은 요소가 여전히비활성화되어 있을 수 있습니다.즉각적인 반응을 원하는 경우:debounce/throttle는 호출을 지연시키기 때문에 사용자에게즉각적인 반응을 보여주기에 제한적입니다.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 (기본 사용 예제)
버튼을 빠르게 여러 번 클릭해보세요. isLoading이 true인 동안에는 중복 요청이 차단되며, 버튼이 비활성화됩니다.
버튼을 빠르게 여러 번 클릭해도 진행 중인 요청이 완료되기 전까지 한 번만 실행됩니다.
버튼 클릭 횟수
0
실제 API 호출 횟수
0
Example2 (isError 처리 예제)
에러가 발생하면 isError가 true로 변경되고, 다음 정상 호출 시 false로 초기화됩니다.
isLoading: false
isError: false
버튼을 클릭하면 로그가 표시됩니다.