useQuery vs getQueryData: 언제 무엇을 사용해야 할까?
오늘은 React Query를 사용할 때 자주 고민하게 되는 주제에 대해 이야기해보려고 합니다. 바로 useQuery
와 getQueryData
의 사용에 관한 것인데요. 이 두 가지 방법 중 어떤 것을 선택해야 할지, 그 기준에 대해 알아보겠습니다.
React Query는 비동기 데이터 관리를 쉽게 해주는 강력한 도구입니다. 하지만 useQuery
와 getQueryData
사이에서 어떤 것을 선택해야 할지 고민하는 경우가 많습니다. 이 포스팅에서는 이 두 가지의 차이점을 명확히 하고, 각각의 사용 시점에 대한 가이드를 제공하고자 합니다.
1. useQuery
: 컴포넌트 내 데이터 fetching의 표준
useQuery
는 React Query의 핵심 기능을 제공하는 훅으로, 컴포넌트 내에서 데이터를 fetching하고 상태를 관리할 때 가장 일반적으로 사용됩니다. 주요 특징은 다음과 같습니다:
- 데이터 캐싱: 데이터가 캐싱되어 같은 데이터를 다시 요청할 때 네트워크 요청을 줄입니다.
- 자동 에러 처리: 네트워크 오류 발생 시 자동으로 에러 상태를 관리합니다.
- 로딩 상태 관리: 데이터 로딩 중일 때 로딩 상태를 자동으로 제공합니다.
- 데이터 자동 갱신: 데이터가 변경될 때마다 자동으로 갱신합니다.
아래는 useQuery
를 사용하는 예제입니다:
import { useQuery } from 'react-query'; interface Todo { id: number; title: string; completed: boolean; } const fetchTodos = async (): Promise<Todo[]> => { const response = await fetch('<https://api.example.com/todos>'); if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }; const TodoList: React.FC = () => { const { data, isLoading, error } = useQuery<Todo[], Error>('todos', fetchTodos); if (isLoading) return <div>Loading...</div>; if (error) return <div>An error occurred: {error.message}</div>; return ( <ul> {data?.map(todo => ( <li key={todo.id}>{todo.title}</li> ))} </ul> ); };
언제 useQuery
를 사용해야 할까?
컴포넌트가 데이터를 직접 관리하고 그 상태를 추적해야 하는 경우, useQuery
를 사용하는 것이 가장 적합합니다. 예를 들어, 컴포넌트가 렌더링될 때마다 데이터를 가져와야 하거나, 데이터 로딩 상태와 에러 처리를 함께 관리해야 할 때입니다. useQuery
는 이러한 상황에서 컴포넌트의 복잡성을 줄이고, 상태 관리의 일관성을 유지할 수 있습니다.
2. getQueryData
: 컴포넌트 외부에서의 데이터 접근
getQueryData
는 React Query의 캐시에서 이미 가져온 데이터를 직접 접근할 때 사용하는 유틸리티 함수입니다. getQueryData
는 서버와의 동기화 상태를 보장하지 않기 때문에, 데이터의 최신성보다 캐시된 데이터의 사용이 중요한 경우에만 사용하는 것이 좋습니다.
사용 예제
import { useQueryClient } from 'react-query'; const SomeComponent: React.FC = () => { const queryClient = useQueryClient(); const handleButtonClick = () => { const todoData = queryClient.getQueryData<Todo[]>('todos'); if (todoData) { console.log('Current todos:', todoData); } }; return <button onClick={handleButtonClick}>Log Todos</button>; };
언제 getQueryData
를 사용해야 할까?
getQueryData
는 다음과 같은 상황에서 유용합니다:
- 서버 사이드 렌더링(SSR): 서버에서 데이터를 미리 가져온 후, 클라이언트 측에서 동일한 데이터를 재사용할 때.
- 이벤트 핸들러 내에서의 데이터 접근: 이미 가져온 데이터를 빠르게 접근해야 할 때.
- 비동기 함수에서의 데이터 사용: 다른 비동기 로직에서 최신 상태를 신경 쓰지 않고 캐시된 데이터를 활용할 때.
그러나, 데이터가 최신인지 확인해야 하거나 동기화된 상태가 중요한 경우에는 useQuery
를 사용하여 데이터를 다시 가져오는 것이 더 안전합니다.
3. 부모-자식 관계에서의 데이터 전달
React의 단방향 데이터 흐름 원칙에 따라, 부모 컴포넌트에서 데이터를 가져온 후 자식 컴포넌트에 props로 전달하는 것이 일반적입니다. 이 방법은 컴포넌트 간의 데이터 흐름을 명확하게 유지하며, 데이터 관리의 일관성을 유지하는 데 도움이 됩니다.
사용 예제
interface TodoListProps { todos: Todo[]; } const ParentComponent: React.FC = () => { const { data } = useQuery<Todo[], Error>('todos', fetchTodos); return <TodoList todos={data || []} />; }; const TodoList: React.FC<TodoListProps> = ({ todos }) => { return ( <ul> {todos.map(todo => ( <li key={todo.id}>{todo.title}</li> ))} </ul> ); };
언제 이 방식을 선택해야 할까?
부모 컴포넌트가 여러 자식 컴포넌트에 동일한 데이터를 전달해야 하거나, 데이터를 하나의 소스로부터 관리해야 할 때 유용합니다. 하지만 자식 컴포넌트가 독립적으로 데이터를 관리해야 하는 상황에서는 자식 컴포넌트에서 useQuery
를 사용하여 데이터 fetching을 직접 관리하는 것도 고려할 수 있습니다.
4. 성능 최적화와 일관성 유지
성능을 최적화하기 위해 컴포넌트 내에서 useQuery
와 getQueryData
를 적절히 혼용하는 것도 중요합니다. 예를 들어, getQueryData
를 사용해 이미 캐시된 데이터를 빠르게 가져올 수 있는 상황에서는 굳이 useQuery
를 사용해 네트워크 요청을 반복할 필요가 없습니다.
const OptimizedComponent: React.FC = () => { const { data: todoData } = useQuery<Todo[], Error>('todos', fetchTodos); return ( <div> {todoData ? `Total todos: ${todoData.length}` : 'Loading...'} </div> ); };
일관성과 성능 사이의 균형 잡기
컴포넌트 내부에서는 useQuery
를 사용하여 데이터 fetching과 상태 관리를 일관되게 하는 것이 좋습니다. 그러나 성능상의 이유로, 이미 캐시된 데이터를 사용하는 것이 적절한 상황에서는 getQueryData
를 사용하는 것도 고려해야 합니다. 이처럼 상황에 맞는 선택이 필요합니다.
결론
useQuery
: 컴포넌트 내에서 데이터를 fetching하고 상태를 관리할 때 사용합니다. 컴포넌트의 렌더링과 동기화된 최신 데이터를 필요로 할 때 적합합니다.getQueryData
: 컴포넌트 외부에서 이미 캐시된 데이터에 빠르게 접근해야 할 때 사용합니다. 그러나 최신성보다는 성능이 중요한 경우에만 사용하는 것이 좋습니다.- 부모-자식 관계: 부모 컴포넌트에서 데이터를 fetching한 후, 자식 컴포넌트에 props로 전달하는 것이 일반적이나, 자식 컴포넌트가 독립적으로 데이터를 관리해야 하는 경우는 자식에서
useQuery
를 사용하는 것도 고려할 수 있습니다. - 일관성 유지와 성능 최적화: 컴포넌트 내에서 일관성을 유지하면서도 성능을 최적화하는 방법을 상황에 맞게 선택해야 합니다.
React Query를 사용할 때, 이 두 가지 방법을 잘 활용하면 코드의 유지보수성과 성능을 모두 챙길 수 있습니다. 상황에 따라 적절한 도구를 선택하는 것이 중요하며, 이를 통해 예측 가능한 데이터 관리 패턴을 구축할 수 있습니다.