[React] React-Query 의 Cache 에 대해서 Deep Dive

김현수·2024년 2월 24일
0

React

목록 보기
15/29


🖍️ React-Query 에서 캐시를 활용하는 법


# 기본

  • 데이터 가져오기 및 저장
  • useQuery 를 사용
  • 사용자가 입력한 고유 키를 사용하여 응답 데이터를 자동 캐싱

  • 캐시된 데이터를 검색하고 관리하는 데 사용
  • 다른 구성 요소가 동일한 키를 사용하여 동일한 데이터를 요청하는 경우
    • React Query는 새 네트워크 요청을 하는 대신 캐시된 데이터를 반환

  • "고유키를 사용하여 캐시를 사용하는 것"

    • 답 : 여러 컴포넌트 간에 필요한 데이터를 props로 전달하는 것보다 더 효율적이고 성능을 개선

# 쿼리 키

  • 첫 번째 요소가 문자열 (쿼리의 고유 식별자를 나타냄)
  • 후속 요소는 가져오는 특정 데이터를 정의하는 매개 변수인 배열 (optional)
  • 쿼리 유형과 해당 매개 변수를 기반으로 데이터를 효율적으로 캐시하고 검색
import { useQuery } from '@tanstack/react-query';

// 사용자 정보를 가져오는 API 호출 함수
const fetchUser = async (userId) => {
  const response = await fetch(`https://example.com/api/users/${userId}`);
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

function UserProfile({ userId }) {
  // useQuery에서 쿼리 키로 ['user', userId]를 사용합니다.
  const { data, error, isLoading } = useQuery(['user', userId], () => fetchUser(userId));

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  // 데이터 로딩 완료 후 사용자 프로필 렌더링
  return (
    <div>
      <h1>{data.name}</h1>
      <p>Email: {data.email}</p>
    </div>
  );
}

# 부실 데이터 및 백그라운드 업데이트

  • "staleTime" 옵션을 통해 쿼리 데이터가 얼마나 오랫동안 "신선"하게 유지될지를 설정

  • 해당 데이터가 부실해질 때, 컴포넌트가 다시 포커스를 얻거나 새로운 쿼리가 발생할 때 자동으로 백그라운드에서 데이터를 업데이트
function UserProfile({ userId }) {
  const { data, isLoading } = useQuery(['user', userId], () => fetchUserProfile(userId), {
    staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 신선하게 유지
  });

  if (isLoading) return <div>Loading...</div>;

  return <div>{data.name}</div>;
}

# 캐시 시간 제한

  • "cacheTime" 비활성화된 쿼리 데이터가 캐시에 얼마나 오래 남아있을지 설정
  • 가비지 컬렉션을 통해 캐시에서 자동으로 제거
  • 메모리 사용량을 관리하는 데 유용
function UserProfile({ userId }) {
  const { data, isLoading } = useQuery(['user', userId], () => fetchUserProfile(userId), {
    staleTime: 1000 * 60 * 5, // 데이터를 5분 동안 신선하게 유지
    cacheTime: 1000 * 60 * 60 * 24, // 데이터를 24시간 동안 캐시에 유지
  });

  if (isLoading) return <div>Loading...</div>;

  return <div>{data.name}</div>;
}

📢 Q. Cache time 과 Stale time 에 대해

  • stale time 에 지정한 기간 동안은 신선한 Data 로 간주
  • 새로운 요청이 발생해도 기존의 쿼리키를 통해 캐싱한 데이터를 사용
  • 지정한 기능이 지나면 "부실"한 데이터로 간주하여 해당 쿼리가 호출될 때 자동으로 데이터를 재패치
    • stale time 이 지났을 때
    • 해당 데이터를 사용하는 컴포넌트가 포함된 페이지로 돌아올 때
  • => 시간이 지났다고 무조건 재패치가 아니라 위와 같은 조건을 만족해야 함

  • cache time 은 비활성화된 쿼리 데이터가 캐시에 남아 있을 시간을 정의
  • 쿼리가 비활성 상태가 되어 cacheTime 동안 사용되지 않으면, 이후에는 캐시에서 해당 데이터를 자동으로 삭제
  • 이는 캐시 메모리 관리에 유용
    • 비활성화된 상태
    • cache time 이 지나는 동안 사용하지 않는 경우

# 낙관적 업데이트

  • "useMutation" 훅과 함께 onMutate, onSuccess, onError, onSettled 콜백을 사용
  • 데이터를 업데이트하고, 필요한 경우 롤백
import { useMutation, useQueryClient } from '@tanstack/react-query';

function ProfileUpdateForm({ userId }) {
  const queryClient = useQueryClient();
  const { mutate } = useMutation(updateUserProfile, {
    onMutate: async (newData) => {
      // 취소를 위한 현재 캐시된 데이터 백업
      const previousUserData = queryClient.getQueryData(['user', userId]);
      
      // 낙관적 업데이트: UI를 즉시 업데이트
      queryClient.setQueryData(['user', userId], oldData => ({
        ...oldData,
        ...newData,
      }));

      return { previousUserData };
    },
    onError: (err, newData, context) => {
      // 에러 발생 시 롤백
      queryClient.setQueryData(['user', userId], context.previousUserData);
    },
    onSettled: () => {
      // 성공 또는 에러 후 캐시된 데이터를 다시 가져옴
      queryClient.invalidateQueries(['user', userId]);
    },
  });

  // 예를 들어 사용자 프로필 업데이트 로직
  const handleSubmit = (newData) => {
    mutate({ userId, newData });
  };

캐시를 사용하는 경우

  • 초기 데이터 로딩
    • 처음으로 데이터를 마운트하고 요청할 때, 캐시 확인 후 없으면 데이터 요청

  • 동시 요청
    • 여러 컴포넌트가 동일한 데이터를 필요로 할 때 매우 유용
    • "동일한 쿼리 키" (['user', userId]) 를 사용하는 다른 요청이 동시에 발생하면, 이 요청들을 대기 상태로 전환
    • 동일한 캐시된 데이터를 사용하여 렌더링되며, 이 과정에서 단 하나의 네트워크 요청만 발생

  • 백그라운드 데이터 새로 고침
    • 부실한 데이터의 경우, 업데이트된 데이터를 가져오는 동안 현재 데이터를 즉시 제공

  • 데이터 프리패치
    • 곧 필요할 수 있는 데이터를 프리페치하여 요청 시 즉시 액세스할 수 있도록 캐시에 저장
  • 캐시 조작
    • 개발자는 필요에 따라 다시 가져오기를 트리거하거나 UI를 업데이트

📢 캐싱 메커니즘은 서버 상태를 효율적으로 관리하여 데이터 가져오기를 최적화하고 네트워크 요청을 줄이며 원활한 사용자 경험을 제공하도록 설계

profile
일단 한다

0개의 댓글