부제 : useQuery 에서 어떻게 캐싱이 될까?
const { data, isLoading, error } = useQuery(['posts'], fetchPosts)
캐싱
useQuery는 가져온 데이터를 자동으로 캐시에 저장합니다. 동일한 쿼리 키를 사용하여 동일한 데이터를 요청하면, 서버로 새로운 요청을 보내지 않고 캐시된 데이터를 즉시 반환합니다. 이를 통해 서버 요청 횟수를 줄이고 성능을 최적화할 수 있습니다.
데이터의 자동 업데이트
useQuery는 캐시된 데이터가 일정 시간이 지나거나 데이터가 변경될 때 자동으로 다시 데이터를 가져와 최신 상태로 업데이트합니다. 이를 stale-while-revalidate 패턴이라고 합니다. 예를 들어, staleTime이 지나면 캐시된 데이터가 오래된 것으로 간주되고, 다시 데이터를 가져옵니다.
자동 재시도
useQuery는 네트워크 에러 등으로 인해 데이터 가져오기가 실패했을 때, 자동으로 재시도(retry)를 수행합니다. 기본적으로 3번까지 재시도하며, 이 동작은 설정에 따라 조정할 수 있습니다.
const { data, isError } = useQuery(['posts'], fetchPosts, {
retry: 2 // 최대 2번까지 재시도
})
const { data, isLoading, isError } = useQuery(['posts'], fetchPosts)
if (isLoading) return <div>Loading...</div>
if (isError) return <div>Error occurred</div>
const { data } = useQuery(['posts', userId], () => fetchPosts(userId))
const { data, refetch } = useQuery(['posts'], fetchPosts)
<button onClick={() => refetch()}>Refetch Data</button>
const { data } = useQuery(['posts'], fetchPosts, {
enabled: isUserLoggedIn, // isUserLoggedIn이 true일 때만 쿼리 실행
})
const { data } = useQuery(['posts'], fetchPosts, {
refetchInterval: 60000, // 60초마다 데이터를 다시 가져옴
})
import { useQuery } from '@tanstack/react-query'
const fetchPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts')
if (!response.ok) throw new Error('Network response was not ok')
return response.json()
}
const Posts = () => {
const { data, isLoading, isError, error } = useQuery(['posts'], fetchPosts)
if (isLoading) return <div>Loading...</div>
if (isError) return <div>Error: {error.message}</div>
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
export default Posts
useQuery는 비동기 데이터를 가져오고, 캐시하고, 관리하는 모든 작업을 간편하게 처리해 줍니다.
캐싱과 자동 재시도, 자동 갱신 같은 기능을 제공해 서버 데이터와의 동기화를 쉽게 유지할 수 있습니다.
상태 관리를 통해 로딩, 에러, 성공 상태를 적절히 관리할 수 있습니다.
수동 데이터 갱신, 배경 동기화 등 다양한 옵션을 제공하여 데이터 fetching을 정교하게 제어할 수 있습니다.
이를 통해 효율적으로 비동기 데이터를 관리하고, 코드의 복잡성을 줄일 수 있습니다.
맞습니다! useQuery 훅을 사용한 컴포넌트를 호출하면 해당 컴포넌트가 렌더링될 때 자동으로 useQuery가 실행되고, 데이터를 fetching합니다. React Query가 비동기 함수(queryFn)를 실행해서 데이터를 가져오고, 그 결과를 컴포넌트 내에서 사용할 수 있게 되는 구조입니다.
useQuery는 다음과 같은 경우에 자동으로 실행됩니다:
const { data, isLoading } = useQuery(['posts'], fetchPosts)
const { data, isLoading } = useQuery(['user', userId], () => fetchUser(userId))
userId가 변경되면 React Query는 이 쿼리가 새로운 데이터라고 판단하고 다시 데이터를 가져옵니다.
const { data } = useQuery(['posts'], fetchPosts, { staleTime: 10000 })
이 예에서는 10초가 지나면 캐시된 데이터가 만료되고, 쿼리가 다시 실행됩니다.
const { data } = useQuery(['posts'], fetchPosts)
사용자가 탭을 이동했다가 다시 돌아오면 useQuery가 다시 실행됩니다.
네트워크가 재연결될 때
네트워크 연결이 끊겼다가 다시 연결될 때에도 useQuery는 자동으로 실행되어 데이터를 다시 fetching합니다.
refetch를 수동으로 호출할 때
필요에 따라 데이터를 다시 가져오고 싶다면, refetch 함수를 수동으로 호출할 수 있습니다. useQuery는 이 함수가 호출될 때마다 쿼리를 다시 실행합니다.
const { data, refetch } = useQuery(['posts'], fetchPosts)
return <button onClick={() => refetch()}>Refetch Data</button>
const { data } = useQuery(['posts'], fetchPosts, { enabled: isUserLoggedIn })
isUserLoggedIn 값이 true가 되면 useQuery가 실행됩니다.
queryKey에 꼭 파라미터만 넣을 필요는 없습니다. queryKey는 React Query에서 캐싱과 데이터를 구별하기 위한 고유 식별자로 사용되며, 단순히 파라미터뿐만 아니라 모든 값을 포함할 수 있습니다. queryKey는 배열이나 문자열, 또는 객체로 구성할 수 있습니다.
그러면 이미 캐싱이 되어있잖아 1 이
근데 db 상에서는 캐시가 1인 데이터가 바껴있어
그러면 1이 이미 캐싱되어잇기때매 재호출안해 ?
queryKey가 "1"인 쿼리는 이미 캐싱된 데이터가 있기 때문에 바로 캐싱된 데이터를 사용합니다. 이렇게 하면 빠르게 UI를 업데이트할 수 있습니다.
React Query는 staleTime이라는 설정을 통해 데이터를 얼마나 오래 "신선한 상태"로 유지할지 결정할 수 있습니다. staleTime이 지나면 데이터는 "stale" 상태가 되고, React Query는 자동으로 다시 데이터를 fetching할 수 있습니다.
기본적으로 staleTime은 0으로 설정되어 있기 때문에, 데이터를 캐시에서 사용하더라도 곧바로 다시 fetching하여 최신 데이터를 가져옵니다.
const { data } = useQuery('1', fetchData, { staleTime: 5000 }) // 5초 동안
캐시된 데이터가 유효
위 예시에서는 5초 동안 캐시된 데이터가 신선한 것으로 간주되며, 그 후에는 다시 fetching이 이루어집니다.
React Query는 페이지가 다시 포커스될 때(사용자가 다른 탭으로 갔다가 돌아왔을 때) 캐시된 데이터가 stale 상태가 아니더라도 자동으로 다시 fetching하여 최신 데이터를 가져옵니다. 이 기능은 기본으로 활성화되어 있습니다.
const { data } = useQuery('1', fetchData, { refetchOnWindowFocus: true })
만약 데이터가 바뀌었다는 것을 알고 있거나, 강제로 다시 fetching하고 싶다면 refetch 함수를 호출할 수 있습니다.
const { data, refetch } = useQuery('1', fetchData)
// 수동으로 refetch 호출
<button onClick={() => refetch()}>다시 불러오기</button>
서버에서 데이터를 가져온 후 onSuccess나 onSettled와 같은 옵션을 통해 데이터를 갱신했는지 확인할 수 있습니다.
onSuccess 콜백은 데이터 fetching이 성공적으로 완료된 후 실행되며, 이를 통해 추가적인 로직을 처리할 수 있습니다.
캐시된 데이터를 먼저 화면에 표시하고, 동시에 서버에서 최신 데이터를 가져오는 방식은 사용자 경험(UX)을 개선하고, 성능 최적화 측면에서 여러 가지 이점이 있습니다. 다음은 이러한 방식이 좋은 이유입니다:
빠른 응답 시간으로 사용자 경험 향상
캐시된 데이터를 사용하면, 사용자가 페이지를 열었을 때 서버 응답을 기다리지 않고 즉시 화면에 데이터를 표시할 수 있습니다. 서버에서 최신 데이터를 받아오는 동안 사용자에게는 이미 화면에 데이터가 보이기 때문에 앱이 더 빠르고 응답성 있게 느껴집니다.
서버 요청에 시간이 걸리는 경우에도 사용자는 기다림 없이 기존 데이터를 먼저 확인할 수 있습니다.
예시:
쇼핑몰 사이트에서 제품 리스트를 보다가 새로고침을 하면, 이전에 본 제품 리스트가 바로 표시되고, 최신 재고 상태나 가격은 나중에 서버에서 업데이트됩니다.
사용자 입장에서는 페이지 로딩 시간이 거의 느껴지지 않음.
최신 정보가 필요할 경우에만 백그라운드에서 자동으로 데이터가 업데이트.
네트워크 지연에 대한 완화
네트워크 상태가 불안정하거나 서버 응답 시간이 길어지더라도, 캐시된 데이터를 보여주면 사용자가 빈 화면을 보지 않게 됩니다.
서버에서 최신 데이터를 받는 데 시간이 걸리더라도, 캐시된 데이터를 통해 중간 경험을 제공함으로써, 사용자가 더 나은 경험을 하게 됩니다.
예시:
모바일 데이터가 느리거나 와이파이 연결이 약한 경우, 캐시된 데이터를 먼저 보여주면, 사용자는 일단 화면이 로드되었다고 인식합니다. 최신 데이터가 곧 업데이트되면, 사용자는 성능 문제를 크게 느끼지 않게 됩니다.
데이터 변동이 적은 경우 캐시가 유용
만약 데이터가 자주 변하지 않는 경우, 캐시된 데이터를 사용하는 것이 더 효율적입니다.
자주 변하지 않는 데이터를 서버에서 매번 불러오는 대신, 캐시를 사용하여 네트워크 요청을 줄이고 성능을 최적화할 수 있습니다.
예시:
사용자의 프로필 정보나 설정과 같은 데이터는 자주 변하지 않기 때문에, 캐시된 데이터를 먼저 보여주고, 서버에서 최신 정보가 있는지 확인하는 방식이 적합합니다.
네트워크 요청을 줄여 성능 최적화
캐시를 사용하면 불필요한 네트워크 요청을 줄일 수 있습니다. 예를 들어, 사용자가 자주 방문하는 페이지나 기능에서 동일한 데이터를 반복적으로 요청하는 대신, 캐시된 데이터를 재사용할 수 있습니다.
이로 인해 서버 부하가 줄어들고, 앱 성능이 전반적으로 향상됩니다.
예시:
사용자가 같은 리스트를 여러 번 확인할 때마다 매번 서버에 요청하지 않고, 캐시된 데이터를 먼저 제공하면, 네트워크 비용을 절감하고 서버의 부하를 줄일 수 있습니다.
점진적 데이터 업데이트로 사용자 경험 부드럽게 유지
캐시된 데이터를 먼저 보여준 뒤, 서버에서 최신 데이터를 가져오면, 사용자가 느끼는 변경 사항이 더 부드럽게 이루어집니다. 서버 데이터를 기다리느라 화면이 계속 로딩 상태에 머무르지 않고, 사용자는 화면을 바로 사용할 수 있고, 그동안 백그라운드에서 데이터를 업데이트하면 됩니다.
데이터가 업데이트되면 화면을 부드럽게 갱신함으로써 사용자 경험을 자연스럽게 유지할 수 있습니다.
예시:
뉴스 앱에서 캐시된 기사 목록을 먼저 보여준 후, 최신 기사를 백그라운드에서 가져오는 경우, 사용자는 기다림 없이 앱을 탐색할 수 있으며, 기사가 업데이트될 때 자연스럽게 새로운 정보가 화면에 표시됩니다.
오프라인 모드 지원
캐시된 데이터를 활용하면 오프라인 상태에서도 일부 기능을 사용할 수 있습니다. 네트워크 연결이 없을 때도 캐시에 저장된 데이터를 이용해 일시적인 오프라인 경험을 제공할 수 있습니다.
예시:
사용자가 비행기 모드로 전환되었을 때도, 이전에 불러왔던 콘텐츠가 캐시에서 보여지므로 오프라인 상태에서도 앱을 사용할 수 있습니다.
이런 이유로, 캐시된 데이터를 먼저 사용하고 서버에서 최신 데이터를 가져오는 방식은 사용자 경험을 개선하고 성능을 최적화하는 데 매우 유용합니다.