[리액트 쿼리] enabled 옵션을 사용하여 쿼리를 원할 때만 수행하기

Woonil·2025년 3월 5일
0

리액트 쿼리

목록 보기
4/4

서버에서 데이터를 불러와 화면에 표시하는 데 리액트 쿼리의 useQuery를 사용한다면, 보통 페이지 진입과 동시에 데이터를 가져오게 했을 것이다. 만약 사진을 다운로드하려고 특정 버튼이 눌렀을 때와 같이, 원할 때만 데이터를 가져오는 데 useQuery를 사용하려면 어떻게 해야 할까? 물론 클릭 핸들러 내부에 데이터를 페칭하는 코드를 작성해도 되지만, 데이터 페칭 api를 컴포넌트와 분리하여 단일 책임을 지게 리팩토링을 하고 싶다.

🤔문제 상황

import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

const useGetDownloadedFile = (fileId: number) => {
    const downloadedFilePathURL = '/api/file';

    return useQuery<string>({
        queryKey: ['downloadedFile'],
        queryFn: async () =>
            await axios
                .get(downloadedFilePathURL, {
                    params: { fileId },
                    responseType: 'blob',
                })
                .then(res => res.data)
                .catch(() => window.alert('사진 저장에 실패하였습니다.')),
    });
};

export default useGetDownloadedFile;

다음과 같이 버튼 컴포넌트 자체에 useQuery를 호출한다면 페이지 로드 시 바로 데이터를 요청할 것이다. 우리가 원하는 동작이 아니다.

export default function DownloadBtn({ selectedPhoto }: { selectedPhoto: IExistingFileDto }) {
    const { data } = useGetDownloadedFile(selectedPhoto?.id);

    // HANDLER: 사진 다운로드 버튼 핸들러
    const handleDownloadBtnClick = async () => {
        if (data) {
            downloadFromTempDownloadUrl(rawData, fileName);
        }
    };

    return <Button onClick={() => handleDownloadBtnClick()} />;
}

😎해결 방법

버튼이 클릭될 때만 데이터를 요청하게 하려면 어떻게 고쳐야 할까? 이미 누군가 비슷한 상황에 대해 스택오버플로우에 질문했고 그에 대한 답변이 있었다.

React-Query: How to useQuery when button is clicked - Stackoverflow

결론은 useQuery의 enabled 옵션과 refetch 반환값을 사용하면 된다.

  • enabled: false로 지정하면 쿼리가 자동으로 수행되는 것을 막는다.

  • refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>

    • 쿼리를 수동으로 리페칭하는 함수이다.

다음과 같이 useQuery의 옵션에 enabled를 false로 지정한다.

const useGetDownloadedFile = (fileId: number) => {
    const downloadedFilePathURL = '/api/file';

    return useQuery<string>({
        queryKey: ['downloadedFile'],
        queryFn: async () =>
            await axios
                .get(downloadedFilePathURL, {
                    params: { fileId },
                    responseType: 'blob',
                })
                .then(res => res.data)
                .catch(() => window.alert('사진 저장에 실패하였습니다.')),
        enabled: false,
    });
};

이제 useQuery의 사용처에서 반환값 refetch를 꺼내와 버튼 클릭 핸들러에서 수행하게 하면 된다.

export default function DownloadBtn({ selectedPhoto }: { selectedPhoto: IExistingFileDto }) {
    const { refetch } = useGetDownloadedFile(selectedPhoto?.id);

    // HANDLER: 사진 다운로드 버튼 핸들러
    const handleDownloadBtnClick = async () => {
        const { data: rawData } = await refetch();

        if (rawData) {
            downloadFromTempDownloadUrl(rawData, fileName);
        }
    };

    return <Button onClick={() => handleDownloadBtnClick()} />;
}

참고 자료
useQuery - 리액트 쿼리 공식문서

profile
프론트 개발과 클라우드 환경에 관심이 많습니다:)

0개의 댓글

관련 채용 정보