> 웹 프론트엔드 > JS 튜토리얼 > React의 비동기 데이터 가져오기 및 캐싱을 위한 경량 후크 쇼케이스

React의 비동기 데이터 가져오기 및 캐싱을 위한 경량 후크 쇼케이스

Mary-Kate Olsen
풀어 주다: 2025-01-07 18:36:41
원래의
476명이 탐색했습니다.

Showcase of a Lightweight Hook for Async Data Fetching & Caching in React

안녕하세요 여러분!

저는 React 쿼리의 일부 필수 기능(가져오기, 캐싱, 재시도 등)을 모방하지만 더 컴팩트한 useAsync라는 경량 React 후크를 작업해 왔습니다. 쉽게 사용자 정의 가능한 패키지. 다음은 관련 코드 섹션을 참조하여 내부적으로 작동하는 방식에 대한 간략한 분석입니다. 전체 코드를 보려면 다음 저장소로 이동하세요.

GitHub의 전체 소스 코드.
후크는 npm에서 api-refetch로 사용할 수도 있습니다.


나만의 후크를 만드는 이유는 무엇입니까?

React Query와 SWR은 모두 훌륭한 라이브러리이지만 몇 가지 이유로 좀 더 실용적인 접근 방식을 원했습니다.

  1. 가벼운 설치 공간

    React Query와 SWR은 기능이 풍부하지만 상대적으로 크기가 클 수 있습니다(React Query ~2.2MB, SWR ~620kB). api-refetch는 약 250kB이므로 번들 크기가 큰 관심사인 소형 앱에 이상적입니다. 이 후크는 다른 라이브러리(Intlayer)의 종속성으로 설치되도록 되어 있습니다. 결과적으로 솔루션의 크기가 중요한 고려 사항이었습니다.

  2. 손쉬운 맞춤화 및 최적화
    로컬 저장소에서 데이터 저장/가져오기, 간단한 접근 방식을 사용한 병렬 요청 관리
    와 같은 몇 가지 구체적인 기능이 필요했습니다. 프로젝트에 직접 저장소를 복제하거나 코드를 복사하면 원치 않는 기능을 제거하고 필요한 기능만 유지할 수 있습니다. 이는 번들 크기를 줄일 뿐만 아니라 불필요한 재렌더링 및 증가를 최소화하여 특정 요구 사항에 맞는 더 간결하고 성능이 뛰어난 솔루션을 제공합니다.

  3. 필수 제공자 없음

    후크를 전역으로 만들고 사용법을 최대한 단순하게 유지하기 위해 컨텍스트 제공자를 피하고 싶었습니다. 그래서 Zustand 매장을 기반으로 Hooke 버전을 만들었습니다(아래 예시 참조).

  4. 학습 연습

    처음부터 비동기 라이브러리를 구축하는 것은 동시성, 캐싱 및 상태 관리 내부를 이해하는 훌륭한 방법입니다.

간단히 말해서, 라이브러리를 작고 이해하기 쉽게 유지하면서 나에게 필요한 기능을 정확하게 파악하고 필요하지 않은 기능은 건너뛸 수 있는 기회였습니다.

해당 기능

React 후크 관리:

  • 가져오기 및 상태 관리: 로드, 오류, 성공 및 가져온 상태를 처리합니다.
  • 캐싱 및 저장소: 선택적으로 데이터를 캐시하고(React 상태 또는 내부적으로 Zustand를 통해) 로컬 저장소 지원을 제공합니다.
  • 재시도 및 재검증: 재시도 제한 및 자동 재검증 간격을 구성할 수 있습니다.
  • 활성화 및 무효화: 다른 쿼리 또는 상태에 따라 자동으로 쿼리를 활성화하고 무효화합니다. 예: 사용자가 로그인할 때 자동으로 일부 데이터를 가져오고 사용자가 로그아웃할 때 데이터를 무효화합니다.
  • 병렬 구성 요소 마운트 가져오기: 여러 구성 요소를 동시에 마운트할 때 동일한 리소스에 대한 여러 동시 요청을 방지합니다.

코드 작동 방식

다음은 api-refetch의 핵심 사항과 useAsync.tsx의 코드 관련 부분에 대한 간략한 참조입니다.

1. 병렬 마운팅 가져오기 및 처리

  • 코드 조각:
  // This map stores any in-progress Promise to avoid sending parallel requests
  // for the same resource across multiple components.
  const pendingPromises = new Map();

  const fetch: T = async (...args) => {
    // Check if a request with the same key + args is already running
    if (pendingPromises.has(keyWithArgs)) {
      return pendingPromises.get(keyWithArgs);
    }

    // Otherwise, store a new Promise and execute
    const promise = (async () => {
      setQueryState(keyWithArgs, { isLoading: true });

      // ...perform fetch here...
    })();

    // Keep it in the map until it resolves or rejects
    pendingPromises.set(keyWithArgs, promise);
    return await promise;
  };
로그인 후 복사
로그인 후 복사
  • 설명: 여기에서는 진행 중인 모든 가져오기를 보류 중인 Promises 맵에 저장합니다. 두 구성 요소가 동일한 리소스를 동시에 가져오려고 하면(동일한 keyWithArgs를 사용하여) 두 번째 구성 요소는 중복 네트워크 호출을 만드는 대신 진행 중인 요청을 재사용합니다.

2. 재검증

  • 코드 조각:
  // Handle periodic revalidation if caching is enabled
  useEffect(
    () => {
      if (!revalidationEnabled || revalidateTime <= 0) return; // Revalidation is disabled
      if (!isEnabled || !enabled) return; // Hook is disabled
      if (isLoading) return; // Fetch is already in progress
      if (!isSuccess || !fetchedDateTime) return; // Should retry either of revalidate
      if (!(cacheEnabled || storeEnabled)) return; // Useless to revalidate if caching is disabled

      const timeout = setTimeout(() => {
        fetch(...storedArgsRef.current);
      }, revalidateTime);

      return () => clearTimeout(timeout);
    },
    [
      /* dependencies */
    ]
  );
로그인 후 복사
로그인 후 복사
  • 설명: 재검증을 활성화할 때마다 api-refetch는 캐시된 데이터가 지정된 revalidateTime보다 오래된지 확인합니다. 그렇다면 추가 수동 트리거 없이 UI 동기화를 유지하기 위해 백그라운드에서 데이터를 자동으로 다시 가져옵니다.

3. 재시도 논리

  • 코드 조각:
  useEffect(
    () => {
      const isRetryEnabled = errorCount > 0 && retryLimit > 0;
      const isRetryLimitReached = errorCount > retryLimit;

      if (!isEnabled || !enabled) return; // Hook is disabled
      if (!isRetryEnabled) return; // Retry is disabled
      if (isRetryLimitReached) return; // Retry limit has been reached
      if (!(cacheEnabled || storeEnabled)) return; // Useless to retry if caching is disabled
      if (isLoading) return; // Fetch is already in progress
      if (isSuccess) return; // Hook has already fetched successfully

      const timeout = setTimeout(() => {
        fetch(...storedArgsRef.current);
      }, retryTime);

      return () => clearTimeout(timeout);
    },
    [
      /* dependencies */
    ]
  );
로그인 후 복사
  • 설명: 오류가 발생하면 후크는 실패한 시도 횟수를 계산합니다. 여전히 retryLimit 미만인 경우 다시 시도하기 전에 자동으로 retryTime 밀리초를 기다립니다. 이 프로세스는 데이터를 성공적으로 가져오거나 재시도 제한에 도달할 때까지 계속됩니다.

4. 자동 가져오기

  • 코드 조각:
  // Auto-fetch data on hook mount if autoFetch is true
  useEffect(
    () => {
      if (!autoFetch) return; // Auto-fetch is disabled
      if (!isEnabled || !enabled) return; // Hook is disabled
      if (isFetched && !isInvalidated) return; // Hook have already fetched or invalidated
      if (isLoading) return; // Fetch is already in progress

      fetch(...storedArgsRef.current);
    },
    [
      /* dependencies */
    ]
  );
로그인 후 복사
  • 설명: autoFetch를 true로 설정하면 구성 요소가 마운트되자마자 후크가 자동으로 비동기 기능을 실행합니다. 이는 항상 로드 시 데이터를 원하는 "fire-and-forget" 시나리오에 적합합니다.

GitHub에서 전체 소스 보기

여기에서 로컬 저장소 논리, 쿼리 무효화 등이 포함된 전체 코드를 확인하세요.

  • 전체 소스코드

관심이 있으시면 자유롭게 사용해 보고, 문제를 보고하고, 참여해 보세요. 어떤 피드백이라도 감사히 받겠습니다!

사용예

설치

코드를 복사하거나 (repo)[https://github.com/aymericzip/api-refetch]를 코드하세요

또는

  // This map stores any in-progress Promise to avoid sending parallel requests
  // for the same resource across multiple components.
  const pendingPromises = new Map();

  const fetch: T = async (...args) => {
    // Check if a request with the same key + args is already running
    if (pendingPromises.has(keyWithArgs)) {
      return pendingPromises.get(keyWithArgs);
    }

    // Otherwise, store a new Promise and execute
    const promise = (async () => {
      setQueryState(keyWithArgs, { isLoading: true });

      // ...perform fetch here...
    })();

    // Keep it in the map until it resolves or rejects
    pendingPromises.set(keyWithArgs, promise);
    return await promise;
  };
로그인 후 복사
로그인 후 복사

빠른 예

  // Handle periodic revalidation if caching is enabled
  useEffect(
    () => {
      if (!revalidationEnabled || revalidateTime <= 0) return; // Revalidation is disabled
      if (!isEnabled || !enabled) return; // Hook is disabled
      if (isLoading) return; // Fetch is already in progress
      if (!isSuccess || !fetchedDateTime) return; // Should retry either of revalidate
      if (!(cacheEnabled || storeEnabled)) return; // Useless to revalidate if caching is disabled

      const timeout = setTimeout(() => {
        fetch(...storedArgsRef.current);
      }, revalidateTime);

      return () => clearTimeout(timeout);
    },
    [
      /* dependencies */
    ]
  );
로그인 후 복사
로그인 후 복사

그렇습니다! 한 번 해보고 어떻게 되는지 알려주세요. GitHub에서는 피드백, 질문 또는 기여를 환영합니다.

GitHub: api-refetch

즐거운 코딩하세요!

위 내용은 React의 비동기 데이터 가져오기 및 캐싱을 위한 경량 후크 쇼케이스의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿