쿼리에 필요한 초기 데이터를 캐시에 제공하기 전에 여러 가지 방법으로 제공할 수 있습니다:
initialData
를 제공합니다.initialData
를 사용하여 쿼리 미리 채우기앱에서 쿼리에 대한 초기 데이터를 이미 사용할 수 있고 쿼리에 직접 제공할 수 있는 경우가 있을 수 있습니다. 이 경우 config.initialData
옵션을 사용하여 쿼리의 초기 데이터를 설정하고 초기 로딩 상태를 건너뛸 수 있습니다!
"IMPORTANT:
initialData
는 캐시에 지속되므로 이 옵션에 자리 placeholder, 부분 데이터 또는 불완전한 데이터를 제공하지 않는 것이 좋으며 대신placeholderData
를 사용하는 것이 좋습니다."
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
})
staleTime
and initialDataUpdatedAt
기본적으로 initialData
는 방금 가져온 것처럼 완전히 새로운 것으로 취급됩니다. 이는 또한 staleTime
옵션에 의해 해석되는 방식에 영향을 미친다는 것을 의미합니다.
query observer를 initialData
로 구성하고 staleTime
을 사용하지 않는 경우(default staleTime: 0
), 쿼리가 마운트될 때 즉시 refetch합니다:
// Will show initialTodos immediately, but also immediately refetch todos after mount
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
})
query observer를 initialData
로 구성하고 staleTime
을 1000ms
로 설정하여 쿼리 옵저버를 구성하면 쿼리 함수에서 방금 fetched 된 것처럼 같은 시간 동안 데이터가 최신으로 간주됩니다.
// Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 1000,
})
initialData
가 완전히 최신이 아니라면 어떻게 해야 할까요? 그러면 실제로 가장 정확한 마지막 구성이 남게 되는데, initialDateUpdatedAt
옵션을 사용합니다. 이 옵션을 사용하면 초기 데이터 자체가 마지막으로 업데이트된 시간(밀리초)의 숫자 JS 타임스탬프를 전달할 수 있습니다(예: Date.now()
가 제공하는 것). 유닉스 타임스탬프가 있는 경우 1000
을 곱하여 JS 타임스탬프로 변환해야 한다는 점에 유의하세요.
// Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 60 * 1000, // 1 minute
// This could be 10 seconds ago or 10 minutes ago
initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
})
이 옵션을 사용하면 staleTime을 원래의 용도로 사용하여 데이터가 얼마나 최신이어야 하는지를 결정하는 동시에, initialData
가 staleTime
보다 오래된 경우 마운트 시 데이터를 refetched 되게할 수 있습니다. 위의 예제에서는 데이터가 1분 이내에 새로 고쳐져야 하며, 초기 데이터가 마지막으로 업데이트된 시점을 쿼리에 힌트하여 쿼리가 데이터를 refetched 되어야 하는지 여부를 스스로 결정할 수 있도록 합니다.
"데이터를 prefetched 데이터로 취급하고 싶다면,
prefetchQuery
또는fetchQuery
API들을 사용하여 캐시를 미리 채우고 초기 데이터와 독립적으로staleTime
을 구성할 것을 권장합니다."
쿼리의 초기 데이터에 접근하는 과정이 intensive하거나 모든 렌더링에서 수행되게 하지 않으려는 경우 함수를 initialData
값으로 전달할 수 있습니다. 이 함수는 쿼리가 초기화될 때 한 번만 실행되므로 귀중한 메모리 그리고/또는 CPU를 절약할 수 있습니다:
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: () => getExpensiveTodos(),
})
어떤 상황에서는 다른 쿼리의 캐시된 결과에서 쿼리의 초기 데이터를 제공할 수 있습니다. 예를 들어 할 일 목록 쿼리에서 캐시된 데이터를 검색하여 개별 할일 항목을 찾은 다음, 이를 개별 할일 쿼리의 초기 데이터로 사용하는 것이 좋은 예입니다:
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
캐시에서 초기 데이터를 가져온다는 것은 초기 데이터를 조회하는 데 사용하는 소스 쿼리가 오래되었을 가능성이 높지만 initialData
임을 의미합니다. 쿼리를 즉시 refetching하는 것을 막기 위해 인위적인 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,
})
초기 데이터를 조회하는 데 사용하는 소스 쿼리가 오래된 경우 캐시된 데이터를 전혀 사용하지 않고 서버에서 가져오는 것이 좋을 수 있습니다. 이 결정을 더 쉽게 내릴 수 있도록, 쿼리가 필요에 따라 충분히 '최신(fresh)'인지 판단하는 데 사용할 수 있는 state.dataUpdatedAt
타임스탬프를 포함하여 소스 쿼리에 대한 자세한 정보를 얻기 위해 대신 queryClient.getQueryState
메서드를 사용할 수 있습니다:
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
를 비교하려면 커뮤니티 리소스를 참조하세요.
Reference