초기 Query 데이터
초기 Query 데이터
섹션 제목: “초기 Query 데이터”캐시에 필요한 쿼리 데이터를 미리 공급하는 방법은 다양합니다.
- 선언형:
- 쿼리에
initialData를 제공해 캐시가 비어 있을 때 미리 채웁니다.
- 쿼리에
- 명령형:
initialData 로 쿼리 미리 채우기
섹션 제목: “initialData 로 쿼리 미리 채우기”앱 내부에 쿼리의 초기 데이터가 이미 존재해 바로 전달할 수 있는 경우가 있습니다. 이때 config.initialData 옵션을 사용하면 초기 데이터를 지정해 초기 로딩 상태를 건너뛸 수 있습니다.
중요:
initialData는 캐시에 지속되므로 플레이스홀더나 불완전한 데이터를 넘기지 말고, 그런 경우에는placeholderData를 사용하세요.
const result = useQuery({ queryKey: ['todos'], queryFn: () => fetch('/todos'), initialData: initialTodos,})staleTime 과 initialDataUpdatedAt
섹션 제목: “staleTime 과 initialDataUpdatedAt”기본적으로 initialData 는 방금 가져온 것처럼 완전히 최신으로 취급됩니다. 따라서 staleTime 옵션에 의해 해석되는 방식에도 영향을 줍니다.
-
initialData만 설정하고staleTime을 생략한 경우(기본값staleTime: 0), 쿼리는 마운트 즉시 다시 가져옵니다.// Will show initialTodos immediately, but also immediately refetch todos after mountconst result = useQuery({queryKey: ['todos'],queryFn: () => fetch('/todos'),initialData: initialTodos,}) -
initialData와staleTime을1000ms 로 설정하면, 해당 시간 동안 쿼리 함수에서 방금 받아온 것처럼 데이터가 신선하다고 간주됩니다.// Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 msconst result = useQuery({queryKey: ['todos'],queryFn: () => fetch('/todos'),initialData: initialTodos,staleTime: 1000,}) -
그렇다면
initialData가 완전히 최신이 아니라면 어떻게 해야 할까요? 이때 가장 정확한 구성은initialDataUpdatedAt옵션입니다. 이 옵션은initialData가 마지막으로 업데이트된 시간을 밀리초 단위 숫자(JS 타임스탬프, 예:Date.now()반환값)로 전달할 수 있게 해줍니다. 유닉스 타임스탬프가 있다면1000을 곱해 JS 타임스탬프로 변환해야 한다는 점에 유의하세요.// Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 msconst result = useQuery({queryKey: ['todos'],queryFn: () => fetch('/todos'),initialData: initialTodos,staleTime: 60 * 1000, // 1 minute// This could be 10 seconds ago or 10 minutes agoinitialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052})이 옵션을 사용하면
staleTime이 원래 목적(데이터가 얼마나 최신이어야 하는지 결정)에 맞게 작동하면서,initialData가staleTime보다 오래된 경우 마운트 시 다시 가져오도록 할 수 있습니다. 위 예에서 데이터는 1분 이내에 최신이어야 하며, 쿼리에initialData의 마지막 업데이트 시간을 알려줌으로써 다시 가져올지 여부를 쿼리가 스스로 판단합니다.데이터를 미리 가져온 데이터 로 취급하고 싶다면
prefetchQuery또는fetchQueryAPI 로 캐시를 먼저 채워 두어staleTime을initialData와 독립적으로 구성할 수 있게 하세요.
Initial Data 함수
섹션 제목: “Initial Data 함수”쿼리의 초기 데이터를 가져오는 과정이 무겁거나 매 렌더마다 실행하고 싶지 않다면, initialData 값으로 함수를 전달할 수 있습니다. 이 함수는 쿼리가 초기화될 때 한 번만 실행되어 메모리와 CPU 자원을 절약합니다.
const result = useQuery({ queryKey: ['todos'], queryFn: () => fetch('/todos'), initialData: () => getExpensiveTodos(),})캐시에서 가져온 Initial Data
섹션 제목: “캐시에서 가져온 Initial Data”상황에 따라 다른 쿼리의 캐시 결과를 이용해 초기 데이터를 제공할 수 있습니다. 예를 들어 todos 리스트 쿼리의 캐시 데이터를 찾아 특정 todo 항목을 얻고, 이를 개별 todo 쿼리의 초기 데이터로 사용할 수 있습니다.
const result = useQuery({ queryKey: ['todo', todoId], queryFn: () => fetch('/todos'), initialData: () => { // Use a todo from the 'todos' query as the initial data for this todo query return queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId) },})initialDataUpdatedAt 과 함께 캐시에서 가져오는 Initial Data
섹션 제목: “initialDataUpdatedAt 과 함께 캐시에서 가져오는 Initial Data”캐시에서 초기 데이터를 얻는다는 것은, 해당 데이터를 찾아오는 소스 쿼리가 오래되었을 가능성이 크다는 뜻입니다. 인위적으로 staleTime 을 조정해 즉시 다시 가져오는 것을 막기보다는, 소스 쿼리의 dataUpdatedAt 값을 initialDataUpdatedAt 에 전달하는 것이 좋습니다. 이렇게 하면 초기 데이터를 제공했더라도 쿼리 인스턴스가 다시 가져와야 하는 시점을 스스로 판단할 수 있는 모든 정보를 갖게 됩니다.
const result = useQuery({ queryKey: ['todos', todoId], queryFn: () => fetch(`/todos/${todoId}`), initialData: () => queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId), initialDataUpdatedAt: () => queryClient.getQueryState(['todos'])?.dataUpdatedAt,})조건부 캐시 Initial Data
섹션 제목: “조건부 캐시 Initial Data”초기 데이터를 찾기 위해 사용하는 소스 쿼리가 오래됐다면, 캐시 데이터를 아예 쓰지 않고 서버에서 다시 가져오고 싶을 수 있습니다. 이 결정을 쉽게 하려면 queryClient.getQueryState 메서드를 사용해 소스 쿼리에 대한 추가 정보를 얻으세요. 여기에는 쿼리가 충분히 “신선”한지 판단할 수 있는 state.dataUpdatedAt 타임스탬프가 포함됩니다.
const result = useQuery({ queryKey: ['todo', todoId], queryFn: () => fetch(`/todos/${todoId}`), initialData: () => { // Get the query state const state = queryClient.getQueryState(['todos'])
// If the query exists and has data that is no older than 10 seconds... if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) { // return the individual todo return state.data.find((d) => d.id === todoId) }
// Otherwise, return undefined and let it fetch from a hard loading state! },})더 읽을거리
섹션 제목: “더 읽을거리”Initial Data 와 Placeholder Data 를 비교하려면 TkDodo의 글을 참고하세요.