react-query v4 공식문서 : Initial Query Data

👾·2022년 8월 12일
0

react-query

목록 보기
16/27
post-thumbnail

공식문서 : https://tanstack.com/query/v4/docs/guides/initial-query-data

Initial Query Data

캐시에 쿼리의 초기 데이터를 제공할 수 있는 방법에는 여러가지가 있다 :

  • 선언적으로
    • 캐시가 비어있는 경우 미리 채우기 위해 쿼리에 initialData 제공
  • 명령적으로
    • queryClient.prefetchQuery를 이용하여 데이터 prefetch
    • queryClient.setQueryData를 이용하여 수동으로 데이터를 캐시에 넣기

Using initialData to prepopulate a query

앱에서 사용할 수 있는 쿼리의 초기 데이터가 이미 존재하고 단순히 쿼리에 직접 제공할 수 있는 경우가 있을 수 있다. 이 경우 config.initialData 옵션을 이용하여 쿼리의 초기 데이터를 설정하고 초기 로딩 상태를 건너뛸 수 있다!

중요 : initialData는 캐시에 유지되므로 이 옵션에 placeholder, 부분적 또는 불완전한 데이터를 제공하는것은 권장되지 않으며 대신 placeholderData를 사용하는 것이 좋다.

function Todos() {
  const result = useQuery(['todos'], () => fetch('/todos'), {
    initialData: initialTodos,
  })
}

staleTime and initialDataUpdateTime

기본적으로 initialData는 방금 fetch된것처럼 완전히 fresh하게 처리된다. 이것은 또한 staleTime 옵션에 의해 해석되는 방식에 영향을 미칠 수 있음을 의미한다.

  • 쿼리 observer를 initialData로 구성하고, staleTime을 없게 설정하면(기본 staleTime : 0), 쿼리는 마운트 시 즉시 refetch된다.
function Todos() {
  // Will show initialTodos immediately, but also immediately refetch todos after mount
  const result = useQuery(['todos'], () => fetch('/todos'), {
    initialData: initialTodos,
  })
}
  • 쿼리 observer를 initialData로, staleTime을 1000ms로 구성하면 데이터는 쿼리 함수에서 방금 fetch된것처럼 동일한 시간 동안 fresh하게 간주된다.
function Todos() {
  // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
  const result = useQuery(['todos'], () => fetch('/todos'), {
    initialData: initialTodos,
    staleTime: 1000,
  })
}
  • initialData가 완전히 fresh하지 않으면 어떻게 될까? 이렇게 되면 실제로 가장 정확하고 initialDataUpdatedAt 옵션을 사용하는 마지막 구성이 남는다. 이 옵션을 사용하면 initialData 자체가 마지막으로 업데이트된 시간(예 : Data.now()에서 제공하는 시간)의 numeric JS timestamp를 밀리초 단위로 전달할 수 있다. unix timestamp가 있는 경우 1000을 곱하여 JS timestamp로 변환해야 한다.
function Todos() {
  // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
  const result = useQuery(['todos'], () => fetch('/todos'), {
    initialData: initialTodos,
    staleTime: 60 * 1000 // 1 minute
    // This could be 10 seconds ago or 10 minutes ago
    initialDataUpdatedAt: initialTodosUpdatedTimestamp // eg. 1608412420052
  })
}

이 옵션을 사용하면 staleTime을 원래의 목적으로 사용하여 데이터를 얼마나 fresh하게 유지해야하는지 결정하는 동시에 initialDatastaleTime보다 오래된 경우 마운트시 데이터를 refetch할 수 있다. 위의 예시에서, 데이터는 1분 이내로 fresh되어야 하며, initialData가 마지막으로 업데이트되었을때 쿼리에 힌트를 줄 수 있으므로 쿼리가 데이터를 refetch해야하는지 아닌지를 스스로 결정할 수 있다.

데이터를 prefetch된 데이터로 처리하려면, prefetchQuery 또는 fetchQuery API를 사용하여 캐시를 미리 채워 staleTimeinitialData와 독립적으로 구성할 수 있도록 하는 것이 좋다.

Initial Data Function

쿼리의 inital data에 접근하는 프로세스가 집약적이거나 모든 렌더링에서 수행하려는 작업이 아니라면, 함수를 initialData 값으로 전달할 수 있다. 이 함수는 쿼리가 초기화될때 한번만 실행되므로 소중한 메모리 및/또는 CPU를 절약할 수 있다.

function Todos() {
  const result = useQuery(['todos'], () => fetch('/todos'), {
    initialData: () => {
      return getExpensiveTodos()
    },
  })
}

Initial Data Cache

경우에 따라 다른 쿼리의 캐시된 결과에서 쿼리의 inital data를 제공할 수 있다. 이에 대한 좋은 예는, 개별 todo item에 대한 todo 리스트 쿼리에서 캐시된 데이터를 검색하여 개별 todo 쿼리의 initial data로 사용하는 것이다.

function Todo({ todoId }) {
  const result = useQuery(['todo', todoId], () => 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)
    },
  })
}

Initial Data from the cache with initialDataUpdatedAt

캐시에서 초기 데이터를 가져오는것은 초기 데이터를 조회하는데 사용하는 소스 쿼리가 오래되었을 가능성이 있지만 initialData임을 의미한다. 인위적인 staleTime을 사용하여 쿼리가 즉시 refetch되지 않도록 하는 대신, 소스쿼리의 dataUpdatedAtinitialDataUpdatedAt에 전달하는게 좋다. 이렇게 하면 제공되는 초기 데이터에 관계없이, 쿼리가 refetch되어야하는지 여부와 시기를 결정하는데 필요한 모든 정보를 쿼리 인스턴스에 제공한다.

function Todo({ todoId }) {
  const result = useQuery(['todo', todoId], () => fetch(`/todos/${todoId}`), {
    initialData: () =>
      queryClient.getQueryData(['todos'])?.find(d => d.id === todoId),
    initialDataUpdatedAt: () =>
      queryClient.getQueryState(['todos'])?.dataUpdatedAt,
  })
}

Conditional Initial Data from Cache

만약 초기 데이터를 조회하는데 사용하는 원본 쿼리가 오래된 경우, 캐시된 데이터를 전혀 사용하지 않고 서버에서 가져오기만 하면 된다. 이 결정을 쉽게 하기 위해서, queryClient.getQueryState 메소드를 사용하여 쿼리가 필요에 맞게 "fresh"한지 결정하는데 사용할 수 있는 state.dataUpdatedAt timestamp를 포함하여 원본 쿼리에 대한 자세한 정보를 얻을 수 있다.

function Todo({ todoId }) {
  const result = useQuery(['todo', todoId], () => 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!
    },
  })
}

Further reading

initial DataPlaceholder Data를 비교하려면 Community Resources를 확인해라.

0개의 댓글