[tanstack-query] 초기 데이터 : initialData, placeholderData

Rosevillage·2024년 5월 22일
0

쿼리에 대한 초기 데이터가 필요한 경우 useQuery에 사용할 수 있는 두 가지 옵션으로 initialData, placeholderData가 있다. 이 둘에 대해 알아보고 차이점 까지 정리해 본다.

InitialData

서비스에서 사용 가능한 쿼리에 대한 초기 데이터가 있고, 이를 쿼리에 직접 제공하고 싶다면, initialData 를 사용할 수 있다.

const query = useQuery({
 queryKey: ['temp'],
 queryFn: () => fetch('/temp'),
 initialData: initialTempData,
})

다만 initialData에 설정되는 값은 query 데이터 업데이트 시에 가져오는 값과 동일한 구조를 지녀야 한다. 즉 부분적이거나 불완전한 데이터를 사용하는 것은 피해야 한다. 이는 intialData가 캐시에 유지되기 때문이다.

staleTime과 initialData

initialData가 캐시에 유지된다는 것은 initialData가 staleTime에 영향을 받는다는 것을 의미한다.

  • staleTime이 기본값 0 일경우 initialData가 사용된 쿼리는 마운트와 동시에 데이터를 다시 가져온다.
  • staleTime이 설정된 경우 쿼리는 지정된 시간동안 데이터가 최신 상태라고 간주하게 된다.

이러한 문제를 해결하기 위해 initialDataUpdateAt 옵션을 사용하는 방법이 존재한다.

initialDataUpdateAt은 staleTime을 원래 목적에 맞게 사용하여 데이터가 얼마나 최신이어야 하는지 결정하도록 하면서, initialData가 staleTime보다 오래된 경우 마운트 시에 데이터를 다시 가져올 수 있도록 한다.

const query = useQuery({
 queryKey: ['temp'],
 queryFn: () => fetch('/temp'),
 initialData: initialTempData,
 staleTime: 60 * 1000,
 initialDataUpdateAt: initialTempDataUpdatedTime,
})

initialDataUpdateAt에는 Date.now() 가 제공하는 것과 같이 초기 데이터 자체가 마지막으로 업데이트된 시점의 숫자(js 타임스탬프)를 밀리초 단위로 전달 할 수 있다.
(Unix 타임스탬프의 경우 1000을 곱해 js 타임스탬프로 변환해야 한다)

함수형 initialData

initialData를 모든 헨들링에서 다시 가져오게 하지 않기 위해서 함수를 initialData 값으로 전달하도록 할 수 있다. 함수로 전달된 initialData는 쿼리가 초기화 될 때 한번만 실행되어 메모리 및 cpu를 절약한다.

const query = useQuery({
 queryKey: ['temp'],
 queryFn: () => fetch('/temp'),
 initialData: () => genInitialTempData(),
})

캐시를 통한 initialData

사용하고자 하는 두 쿼리 데이터의 구조가 같은 경우 캐시된 다른 쿼리의 데이터를 특정 쿼리의 initialData로 사용할 수도 있다.

const queryClient = useQueryClient()
const query = useQuery({
 queryKey: ['item', itemId],
 queryFn: () => fetch(`/items/${itemId}`),
 initialData: () => {
  return queryClient.getQueryData(['items'])?.find(item=>item.id === itemId)
 },
 // 캐시를 이용한 경우에도 initialDataUpdateAt을 사용할 수 있다.
 initialDataUpdateAt: () => {
  return queryClient.getQueryState(['itams'])?.dateUpdatedAt,
 }
})
캐시를 통한 조건부 initialData

initialData에 참조되는 원본 쿼리가 오래된 경우 사용하지 않고, 다시가져오기 위해서 queryClient.getQueryState 메서드를 활용해 원본 쿼리의 최신 여부를 식별할 수 있다.

const queryClient = useQueryClient()
const query = useQuery({
 queryKey: ['item', itemId],
 queryFn: () => fetch(`/items/${itemId}`),
 initialData: () => {
  const queryState = queryClient.getQueryState(['items'])
  
  if(queryState && Date.now() - queryState.dataUpdatedAt <= n * 1000) {
   return queryState.data.find(item=>item.id === itemId)
  }
 },
})

PlaceholderData

initialdata 옵션과 유사하게 쿼리가 이미 데이터가 있는 것처럼 작동하게 하지만, 캐시에는 유지되지 않는 방법이다.
이는 실제 데이터를 백그라운드에서 가져오는 동안 쿼리를 성공적으로 렌더링하기에는 충분한 부분 데이터가 있는 상황에 유용하게 사용할 수 있다.

placeholder를 사용하면 쿼리는 표시할 데이터가 존재 하기에 보류 상태가 되지 않고 성공 상태로 시작하게 된다. 실제 데이터와 구별하기 위해 쿼리 결과에서 isPlaceholderData 플래그가 true로 설정된다.

const placeholderData = useMemo(()=>genPlaceholderData(),[]);
// 그냥 값을 사용할 수 있지만 placeholderData는 렌더링마다 값을 새로이 가져오기 때문에 한번만 가져오도록 하고 싶다면 useMemo를 사용해보는 것이 좋다.
const query = useQuery({
 queryKey: ['temp'],
 queryFn: ()=>fetch('/temp'),
 placeholderData,
})

함수형 placeholderData

placeholderData는 이전에 성공한 쿼리의 데이터 및 쿼리 메타 정보에 접근하는 함수로 만들 수 도 있다.
이전 쿼리의 데이터를 다른 쿼리의 placeholderData로 사용하려는 상황에 주로 사용되며, queryKey가 변경되면 데이터가 이전 쿼리에서 다른 쿼리로 전환되는 동안 전환 이전의 쿼리 데이터를 표시해 놓을 수 있다.

const query = useQuery({
 queryKey: ['temp', id],
 queryFn: () => fetch(`/temp/${id}`),
 placeholderData: (previousData, previousQuery) => previousData,
})

캐시를 통한 placeholderData

함수형과 유사하게 캐시된 다른 쿼리의 데이터를 특정 쿼리의 placeholderData로 사용할 수 있다.
예를 들어 list query의 데이터에서 item query 데이터에 동일하게 사용되는 title이나, description 등을 item query의 placeholderData로 사용하는 방법이 있다.

const queryClient = useQueryClient();
const query = useQuery({
 queryKey: ['item', itemId],
 queryFn: ()=>fetch(`/itemList/${itemId}`),
 placeholderData: () => {
  return queryClient.getQueryData(['itemList'])?.find(item=>item.id === itemId)
 },
})

initialData, placeholderData 차이점

initialData

  • 초기 데이터로서 사용되기 때문에 마운트 시에 query가 fresh 하다면 refetch 되지 않는다.
  • refetch 이후 캐시에 유지된다.
  • staleTime에 대한 고려가 같이 되어야 한다.
  • 업데이트 될 데이터와 같은 구조를 지녀야만 한다.

placeholderData

  • 더미 데이터로서 사용되기 때문에 마운트 시에 반드시 query가 refetch 된다.
  • refetch 이후 캐시에 유지되지 않는다.
  • isPlaceholderData 플래그가 제공된다.
  • 업데이트 될 데이터의 부분집합을 만족해야 한다.

Reference

Tacnstack-Query v5

0개의 댓글

관련 채용 정보