React Query를 재코딩했습니다 | React에서 비동기 데이터 패칭 및 캐싱을 위한 경량 훅 소개
안녕하세요 여러분!
저는 React Query의 일부 필수 기능(데이터 패칭, 캐싱, 재시도 등)을 모방하면서 더 작고 쉽게 커스터마이징 가능한 패키지로 제공하는 경량 React 훅을 개발해왔습니다. 아래는 관련 코드 섹션을 참조하여 내부적으로 작동하는 방식에 대한 간단한 설명입니다. 전체 코드를 보시려면 리포지토리를 방문해주세요:
GitHub의 전체 소스 코드.
이 훅은 npm에서도 api-refetch 로 제공됩니다.
왜 나만의 훅을 만들었을까요?
React Query와 SWR은 모두 훌륭한 라이브러리이지만, 몇 가지 이유로 보다 직접적인 접근 방식을 원했습니다:
경량화
React Query와 SWR은 기능이 풍부하지만 상대적으로 크기가 클 수 있습니다. 패키지 크기가 중요한 경우 자체 훅을 만드는 것이 이상적입니다. 이 훅은 다른 라이브러리(Intlayer)의 의존성으로 설치될 예정이었습니다. 따라서 솔루션의 크기가 중요한 고려 사항이었습니다.커스터마이징 및 최적화 용이
로컬 스토리지에서 데이터 저장/패칭 및 병렬 요청 관리와 같은 특정 기능이 필요했습니다.
리포지토리를 복제하거나 코드를 프로젝트에 직접 복사함으로써 원하지 않는 기능을 제거하고 필요한 것만 유지할 수 있습니다. 이는 번들 크기를 줄일 뿐만 아니라 불필요한 리렌더링을 최소화하고 성능을 향상시켜, 특정 요구 사항에 맞춘 더 간결하고 성능이 뛰어난 솔루션을 제공합니다.필수 Provider 없음
훅을 전역적으로 사용하기 위해 Context Provider를 피하고 사용을 최대한 간단하게 유지하고자 했습니다. 그래서 Zustand 스토어를 기반으로 한 버전을 만들었습니다(아래 예제 참고).학습 연습
비동기 라이브러리를 처음부터 구축하는 것은 동시성, 캐싱, 상태 관리 내부 구조를 이해하는 훌륭한 방법입니다.
요약하자면, 자체 훅을 개발함으로써 필요한 기능에 정확히 집중(원하지 않는 기능은 생략)하면서 라이브러리를 작고 이해하기 쉽게 유지할 수 있는 기회가 되었습니다.
포함된 기능
React 훅이 관리하는 기능:
패칭 및 상태 관리: 로딩, 오류, 성공, 패칭된 상태를 처리합니다.
캐싱 및 저장: 선택적으로 데이터를 캐싱합니다(React 상태 또는 Zustand를 통해) 및 로컬 스토리지 지원을 제공합니다.
재시도 및 재검증: 구성 가능한 재시도 제한 및 자동 재검증 간격을 설정할 수 있습니다.
활성화 및 무효화: 다른 쿼리나 상태에 따라 쿼리를 자동으로 활성화하고 무효화합니다. 예: 사용자가 로그인할 때 일부 데이터를 자동으로 패칭하고, 로그아웃할 때 무효화합니다.
병렬 컴포넌트 마운트 패칭: 여러 컴포넌트가 동시에 마운트될 때 동일한 리소스에 대한 중복 요청을 방지합니다.
GitHub에서 전체 소스 보기
로컬 스토리지 로직, 쿼리 무효화 등을 포함한 전체 코드를 여기에서 확인하세요:
자유롭게 사용해보시고, 이슈를 보고하거나 기여에 관심이 있으시면 참여해주세요. 모든 피드백은 대단히 환영합니다!
사용 예제
설치
코드를 복사하거나 리포지토리의 코드를 사용하세요.
또는
npm install api-refetch
간단한 예제
// 1. 앱을 프로바이더로 감쌉니다 (선택 사항이지만 권장됨)
import { AsyncStateProvider, useAsync } from "api-refetch";
// import { useAsync } from "api-refetch/zustand"; // 또는 zustand 기반 훅을 사용하세요 (프로바이더 필요 없음)
function App() {
return (
<AsyncStateProvider>
<UserDetails />
</AsyncStateProvider>
);
}
// 2. 데이터를 패칭하는 비동기 함수를 정의합니다
const fetchUserData = async (): Promise<string> => {
// 1초 후에 해결되는 프로미스를 생성합니다
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
});
}, 1000);
});
};
// 3. 컴포넌트에서 훅을 사용합니다
const UserDetails = () => {
const { isLoading, data, error, revalidate } = useAsync(
"userDetails",
async () => await fetchUserData(),
{
enable: true, // 훅을 활성화합니다
cache: true, // zustand를 사용하여 API 호출 결과를 캐싱합니다
store: true, // API 호출 결과를 로컬 스토리지에 저장합니다
retryLimit: 3, // API 호출 실패 시 3번 재시도합니다
retryTime: 10 * 1000, // 재시도 전에 10초를 기다립니다
autoFetch: true, // 컴포넌트가 마운트될 때 API 호출을 자동으로 패칭합니다
revalidation: true, // 재검증을 활성화합니다
revalidateTime: 5 * 60 * 1000, // 5분마다 재검증합니다
isInvalidated: false, // 데이터가 무효화되었는지 여부를 결정하여 다시 패칭할지 여부를 결정합니다
invalidateQueries: ["user"], // 데이터가 업데이트될 때 다른 쿼리를 무효화합니다
updateQueries: ["user"], // 데이터가 업데이트될 때 다른 쿼리의 데이터를 설정합니다
onSuccess: (data) => console.log("사용자 데이터가 성공적으로 패칭되었습니다:", data),
onError: (error) => console.error("사용자 데이터 패칭 중 오류 발생:", error),
}
);
if (isLoading) return <div>로딩 중...</div>;
if (error) return <div>오류: {error}</div>;
return (
<div>
<h1>{data?.name}</h1>
<button onClick={() => revalidate()}>새로 고침</button>
</div>
);
};
그게 다입니다! 사용해보시고, 어떻게 되는지 알려주세요. 피드백, 질문 또는 기여는 GitHub에서 언제든지 환영합니다.
GitHub: api-refetch
즐거운 코딩 되세요!