🔥 종속 쿼리

289자
4분

useQuery를 이용한 종속 쿼리

종속 쿼리(또는 연속 쿼리)는 이전 쿼리가 완료되어야 실행할 수 있습니다. 이를 구현하려면 enabled 옵션을 사용하여 쿼리가 실행 준비가 되었는지 알려주면 됩니다.

// 사용자 정보 가져오기
const { data: user } = useQuery({
  queryKey: ['user', email],
  queryFn: getUserByEmail,
})
 
const userId = user?.id
 
// 사용자의 프로젝트 가져오기
const {
  status,
  fetchStatus,
  data: projects,
} = useQuery({
  queryKey: ['projects', userId],
  queryFn: getProjectsByUser,
  // userId가 존재할 때만 쿼리 실행
  enabled: !!userId,
})
 
typescript

프로젝트 쿼리는 처음에 다음 상태로 시작합니다:

status: 'pending'
isPending: true
fetchStatus: 'idle'
 
typescript

사용자 정보를 가져오면 프로젝트 쿼리가 활성화되고 다음 상태로 전환됩니다:

status: 'pending'
isPending: true
fetchStatus: 'fetching'
 
typescript

프로젝트 정보를 모두 가져오면 최종적으로 다음 상태가 됩니다:

status: 'success'
isPending: false
fetchStatus: 'idle'
 
typescript

useQueries를 이용한 종속 쿼리

useQueries를 사용하여 동적 병렬 쿼리도 이전 쿼리에 종속시킬 수 있습니다. 다음은 그 구현 방법입니다:

// 사용자 ID 목록 가져오기
const { data: userIds } = useQuery({
  queryKey: ['users'],
  queryFn: getUsersData,
  select: (users) => users.map((user) => user.id),
})
 
// 각 사용자의 메시지 가져오기
const usersMessages = useQueries({
  queries: userIds
    ? userIds.map((id) => {
        return {
          queryKey: ['messages', id],
          queryFn: () => getMessagesByUsers(id),
        }
      })
    : [], // userIds가 undefined면 빈 배열 반환
})
 
typescript

useQueries는 쿼리 결과 배열을 반환한다는 점에 주의해야 합니다.

성능에 관한 참고 사항

종속 쿼리는 본질적으로 요청 폭포(request waterfall)를 만들어 성능을 저하시킵니다. 두 쿼리가 같은 시간이 걸린다고 가정하면, 병렬로 실행하는 대신 순차적으로 실행하면 항상 두 배의 시간이 걸립니다. 이는 특히 지연 시간이 긴 클라이언트에서 더 큰 문제가 됩니다. 가능하다면 백엔드 API를 재구성하여 두 쿼리를 병렬로 가져올 수 있게 하는 것이 좋습니다. 하지만 이것이 항상 실현 가능한 것은 아닙니다.

위의 예제에서 getUserByEmail을 먼저 가져와 getProjectsByUser를 실행하는 대신, getProjectsByUserEmail이라는 새로운 쿼리를 도입하면 폭포 현상을 줄일 수 있습니다.