TIL#1

sanbondeveloper·2023년 5월 12일
4

TIL

목록 보기
1/1
  • React Query는 모든 re-render에 대해 queryFn을 호출하지 않으며, 기본적인 유효 기간(0초)이 지나도 마찬가지이다.

  • refetchOnWindowFocus 속성

    • 다른 브라우저 탭으로 이동 후 다시 앱으로 돌아오면 re-fetch 수행
    • 로딩 스피너를 표시하지 않고 가져온 데이터가 캐시된 데이터와 같으면 리렌더링이 일어나지 않는다.
    • 개발 중에는 브라우저 개발자 도구와 앱 간에 포커스를 자주 바꾸므로 이 작업이 더 자주 트리거될 수 있다 → 개발 중에는 해당 기능을 off하는 것도 좋을듯

staleTime

  • 쿼리가 fresh 상태에서 stale 상태로 전환될 때까지 걸리는 유효 기간

  • fresh 상태이면 데이터를 캐시에서 가져오기 때문에 네트워크 요청이 발생하지 않는다.

  • stale 상태이면 여전히 데이터를 캐시에서 가져오지만, 특정 상황에서는 백그라운드에서 re-fetch가 발생할 수 있다.

cacheTime

  • 비활성 쿼리가 캐시에서 제거될 때까지 걸리는 기간으로 기본값은 5분이다.

  • 쿼리는 등록된 옵저버가 없는 즉시 비활성 상태로 전환된다.

    • 따라서 해당 쿼리를 사용하는 모든 컴포넌트가 unmount 되면 비활성 상태가 된다.
  • cacheTime을 조작할 일은 거의 없다.

  • DevTools를 통해 캐시에 존재하는 데이터를 확인할 수 있다.


query key

  • 쿼리 키는 의존성 배열처럼 취급한다.
    • 쿼리 키가 변경될 때마다 re-fetch를 트리거 한다.
    • 매개 변수를 queryFn에 전달하면 값이 변경될 때 거의 항상 데이터를 가져온다.
const fetchTodos = async state => {
  const response = await axios.get(`todos/${state}`)
  return response.data
}

export const useTodosQuery = state =>
  useQuery(['todos', state], () => fetchTodos(state))
  • query key는 캐시의 키로 사용되며, ‘all’에서 ‘done’으로 전환할 때 새 캐시 항목이 표시된다.
    • 처음 전환 시(아직 캐시 되어있지 않을 때) 하드 로딩 상태가 발생한다.
    • 이를 해결하기 위해 keepPreviousData 옵션을 사용하거나 initialData 속성을 사용한다.
export const useTodosQuery = state =>
  useQuery(['todos', state], () => fetchTodos(state), {
    initialData: () => {
      const allTodos = queryClient.getQueryData(['todos', 'all'])
      const filteredData =
        allTodos?.filter((todo) => todo.state === state) ?? []

      return filteredData.length > 0 ? filteredData : undefined
    },
  })

데이터 변환 위치

1. In the queryFn

  • queryFn은 사용자가 Promise를 반환할 것으로 예상하고, 결과 데이터는 쿼리 캐시로 전환된다.

  • 서버에서 제공하는 구조의 데이터를 그대로 반환할 필요는 없고 변환할 수 있다.

    • 다만, 변환된 구조가 캐시에 저장되므로 원래 구조에는 접근할 수 없다.
const fetchTodos = async () => {
  const response = await axios.get('todos')
  const data: Todos = response.data

  return data.map((todo) => todo.name.toUpperCase())
}

export const useTodosQuery = () => useQuery(['todos'], fetchTodos)

2. In the render function

  • useMemo를 통해 최적화할 수 있다.
    • queryInfo 자체를 종속성으로 추가하면 변환이 모든 렌더에서 실행된다.
export const useTodosQuery = () => {
  const queryInfo = useQuery(['todos'], fetchTodos)

  return {
    ...queryInfo,
    data: React.useMemo(
      () => queryInfo.data?.map((todo) => todo.name.toUpperCase()),
      [queryInfo.data]
    ),
  }
}

3. using the select option

  • select는 데이터가 존재하는 경우에만 호출된다.
export const useTodosQuery = () =>
  useQuery(['todos'], fetchTodos, {
    select: (data) => data.map((todo) => todo.name.toUpperCase()),
  })
  • select도 함수 ID가 변경되기 때문에 모든 렌더에서 실행된다.
    • useCallback을 사용하거나 안정적인 함수 참조로 분리하여 비용을 줄일 수 있다.
const transformTodoNames = todos =>
  data.map((todo) => todo.name.toUpperCase())

export const useTodosQuery = () =>
  useQuery(['todos'], fetchTodos, {
    select: transformTodoNames,
  })

export const useTodosQuery = () =>
  useQuery(['todos'], fetchTodos, {
    select: React.useCallback(
      data => data.map((todo) => todo.name.toUpperCase()),
      []
    ),
  })
  • select 옵션을 사용하여 데이터의 일부만 구독할 수도 있다.
export const useTodosQuery = select =>
  useQuery(['todos'], fetchTodos, { select })

export const useTodosCount = () => useTodosQuery(data => data.length)
export const useTodo = id =>
  useTodosQuery(data => data.find(todo => todo.id === id))
profile
산본개발자

4개의 댓글

stale 상태일 때 데이터를 캐시에서 가져오는 건 처음 알았어요 ! 유익한 글 감사합니다 ~~

1개의 답글
comment-user-thumbnail
2023년 5월 12일

stale 상태일 때 데이터를 캐시에서 가져오는 건 저도 몰랐네요. 공유 감사합니다!

1개의 답글