두 쿼리가 의존관계에 있어 특정 순서대로 실행되어야 하는 경우에는 어떻게 해야 할까?
예를 들어, 첫 번째 쿼리는 유저의 정보를 받아 오고, 두번째 쿼리는 받아온 유저의 정보에서 아이디를 이용해 해당 유저의 프로젝트를 받아 온다.
const { data: user } = useQuery({
queryKey: ['user', email],
queryFn: getUserByEmail,
});
const userId = user?.id
const {
data: projects,
} = useQuery({
queryKey: ['projects', userId],
queryFn: getProjectsByUser,
});
이런 상황에서는 useQuery()의 enabled옵션을 사용한다. enabled값이 true가 되어야만 해당 쿼리가 실행된다. 이렇게 어떤 특정한 값이나 조건이 충족된 이후에 실행되는 쿼리를 Dependant Query라고 한다.
만약 어떤 쿼리가 userId값이 있을 때만 실행하도록 하고 싶으면 다음과 같이 설정한다.
const { data: user } = useQuery({
queryKey: ['user', email],
queryFn: getUserByEmail,
});
const userId = user?.id
const {
data: projects,
} = useQuery({
queryKey: ['projects', userId],
queryFn: getProjectsByUser,
enabled: !!userId,
});
userId가 있는 경우 true, false로 옵션값이 설정됨위 상황에서는 두 개의 쿼리를 순서대로 실행하려고 enabled옵션을 사용했지만, enabled옵션값으로 꼭 이전 쿼리에서 가져온 데이터가 들어가야만 하는 것은 아니다. 위의 경우도 백엔드 API 설계에 따라서 두번의 쿼리가 아니라 한 번의 쿼리로 끝낼 수 있음!
예를 들어 getProjectByUserEmail()이라는 함수를 통해 유저의 이메일 주소를 백엔드로 전달하고, 그에 맞는 유저의 프로젝트를 받을 수 있는 API가 있다면 한 번의 쿼리로 끝낼 수 있다.
실제로 enabled옵션은 쿼리의 순서를 정하기 위해 사용하기보다는 어떤 쿼리를 바로 실행하지 않고 특정한 값이 있거나 특정 상황이 되었을 때 실행하도록 하는 등 다양한 시나리오에서 활용할 수 있다.
enabled 값을 활용하여 로그인 기능 만들기.
currentUsername이라는 스테이트 값을 만들어 사용.currentUsername을 'sumuri'라는 값으로 설정하고, 이 값이 있을 때 userInfo 쿼리를 실행// src/api.js
const BASE_URL = 'https://learn.codeit.kr/api/codestudit';
// ...
export async function getUserInfo(username) {
const response = await fetch(`${BASE_URL}/users/${username}`);
return await response.json();
}
// HomePage.js
import { useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { getPosts, uploadPost, getUserInfo } from './api';
function HomePage() {
const [currentUsername, setCurrentUsername] = useState('');
// ...
const { data: userInfoData, isPending: isUserInfoPending } = useQuery({
queryKey: ['userInfo'],
queryFn: () => getUserInfo(currentUsername),
enabled: !!currentUsername,
});
// ...
const handleLoginButtonClick = () => {
setCurrentUsername('sumuri');
};
const loginMessage = isUserInfoPending
? '로그인 중입니다...'
: `${userInfoData?.name}님 환영합니다!`;
if (isPending) return '로딩 중입니다...';
if (isError) return '에러가 발생했습니다.';
const posts = postsData?.results ?? [];
return (
<>
<div>
{currentUsername ? (
loginMessage
) : (
<button onClick={handleLoginButtonClick}>codeit으로 로그인</button>
)}
<form onSubmit={handleSubmit}>
<textarea
name="content"
value={content}
onChange={handleInputChange}
/>
<button disabled={!content} type="submit">
업로드
</button>
</form>
</div>
<div>
<ul>
{posts.map((post) => (
<li key={post.id}>
{post.user.name}: {post.content}
</li>
))}
</ul>
</div>
</>
);
}
export default HomePage;