[TanStack Query] 기본 사용법

조아영·2024년 9월 5일

📌

서버 상태를 관리하기 위한 라이브러리로, 데이터를 패칭하고 캐싱, 동기화, 무효화 등의 기능을 제공합니다. 비동기 로직을 간편하게 작성하고 유지보수성을 높일 수 있습니다.

◼ 주요기능

  • 데이터 캐싱: 동일한 데이터를 여러 번 요청하지 않도록 캐싱하여 성능을 향상시킵니다.
  • 자동 리페칭: 데이터가 변경되었을 때 자동으로 리페칭하여 최신 상태를 유지합니다.
  • 쿼리 무효화: 특정 이벤트가 발생했을 때 쿼리를 무효화하고 데이터를 다시 가져올 수 있습니다.

◼ 세팅

1. 설치

yarn add @tanstack/react-query

2. 적용
적용할 범위(ex: 전역)에 Provider를 이용하여 적용합니다.
App.jsx 또는 main.jsx(index.jsx)에 세팅하는 것을 권장합니다.

// main.jsx

import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById("root")).render(
    <QueryClientProvider client={queryClient}>
        <App />
    </QueryClientProvider>
);

◼ useQuery

TanStack Query에서 데이터를 가져오는 대표적인 훅은 useQuery입니다. 이 훅은 쿼리 키와 비동기 함수(패칭 함수)를 인자로 받아 서버에서 데이터를 가져오며, 로딩 상태, 오류 상태, 그리고 데이터를 반환합니다. useQuery를 사용하면 데이터를 쉽게 컴포넌트에서 활용할 수 있을 뿐만 아니라, 캐싱, 자동 리패칭, 백그라운드 데이터 동기화 등 다양한 기능을 지원해 효율적인 데이터 관리가 가능합니다.

기본 사용법

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

const App = () => {
    const fetchTodos = async () => {
        const response = await axios.get("http://localhost:4000/todos");
        return response.data;
    };

    const {
        data: todos,
        isPending,
        isError,
    } = useQuery({
        queryKey: ["todos"],
        queryFn: fetchTodos,
    });

    if (isPending) {
        return <div>로딩중입니다...</div>;
    }

    if (isError) {
        return <div>데이터 조회 중 오류가 발생했습니다.</div>;
    }

    return (
        <div>
            <h3>TanStack Query</h3>
            <ul>
                {todos.map((todo) => {
                    return (
                        <li
                            key={todo.id}
                            style={{
                                display: "flex",
                                alignItems: "center",
                                gap: "10px",
                                backgroundColor: "aliceblue",
                            }}>
                            <h4>{todo.title}</h4>
                            <p>{todo.isDone ? "Done" : "Not Done"}</p>
                        </li>
                    );
                })}
            </ul>
        </div>
    );
};

export default App;

◼ useMutation

useMutation은 데이터를 생성, 수정, 삭제하는 작업(CUD)에 사용되는 훅입니다. 이 훅을 통해 비동기 작업을 간편하게 수행할 수 있으며, 작업이 성공하거나 실패했을 때 추가적인 후속 작업을 실행할 수 있어 useQuery와 함께 TanStack Query의 대표적인 훅으로 꼽힙니다.
특히, 비동기 작업을 쉽게 처리한다는 말에는 작업이 완료된 후 관련된 쿼리를 무효화하는 과정이 포함됩니다. 이는 최신 데이터를 유지하는 데 필수적이며, TanStack Query의 핵심 개념 중 하나입니다.

기본 사용법

import { useMutation, useQuery } from "@tanstack/react-query";
import axios from "axios";
import { useState } from "react";

const App = () => {
    const [todoItem, setTodoItem] = useState("");

    const fetchTodos = async () => {
        const response = await axios.get("http://localhost:4000/todos");
        return response.data;
    };

    const addTodo = async (newTodo) => {
        await axios.post("http://localhost:4000/todos", newTodo);
    };

    const {
        data: todos,
        isPending,
        isError,
    } = useQuery({
        queryKey: ["todos"],
        queryFn: fetchTodos,
    });

    const { mutate } = useMutation({
        mutationFn: addTodo,
    });

    if (isPending) {
        return <div>로딩중입니다...</div>;
    }

    if (isError) {
        return <div>데이터 조회 중 오류가 발생했습니다.</div>;
    }

    return (
        <div>
            <h3>TanStack Query</h3>
            <form
                onSubmit={(e) => {
                    e.preventDefault();

                    const newTodoObj = { title: todoItem, isDone: false };

                    // useMutation 로직 필요
                    mutate(newTodoObj);
                }}>
                <input type="text" value={todoItem} onChange={(e) => setTodoItem(e.target.value)} />
                <button>추가</button>
            </form>
            <ul>
                {todos.map((todo) => {
                    return (
                        <li
                            key={todo.id}
                            style={{
                                display: "flex",
                                alignItems: "center",
                                gap: "10px",
                                backgroundColor: "aliceblue",
                            }}>
                            <h4>{todo.title}</h4>
                            <p>{todo.isDone ? "Done" : "Not Done"}</p>
                        </li>
                    );
                })}
            </ul>
        </div>
    );
};

export default App;

◼ invalidateQueries

invalidateQueries는 특정 쿼리를 무효화하여 데이터를 다시 패칭하게 하는 함수입니다. 주로 useMutation과 함께 사용되어, 데이터가 변경된 후 관련된 쿼리를 다시 가져오도록 합니다. 이를 통해 데이터가 항상 최신 상태로 유지되도록 보장할 수 있습니다.
예를 들어, 새로운 할 일을 추가한 후 invalidateQueries를 사용해 기존의 할 일 목록을 다시 패칭하여 최신 상태로 업데이트할 수 있습니다.

기본 사용법

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import { useState } from "react";

const App = () => {
    const queryClient = useQueryClient();

    const [todoItem, setTodoItem] = useState("");

    const fetchTodos = async () => {
        const response = await axios.get("http://localhost:4000/todos");
        return response.data;
    };

    const addTodo = async (newTodo) => {
        await axios.post("http://localhost:4000/todos", newTodo);
    };

    const {
        data: todos,
        isPending,
        isError,
    } = useQuery({
        queryKey: ["todos"],
        queryFn: fetchTodos,
    });

    const { mutate } = useMutation({
        mutationFn: addTodo,
        onSuccess: () => {
            // alert("데이터 삽입이 성공했습니다.");
            queryClient.invalidateQueries(["todos"]);
        },
    });

    if (isPending) {
        return <div>로딩중입니다...</div>;
    }

    if (isError) {
        return <div>데이터 조회 중 오류가 발생했습니다.</div>;
    }

    return (
        <div>
            <h3>TanStack Query</h3>
            <form
                onSubmit={(e) => {
                    e.preventDefault();

                    const newTodoObj = { title: todoItem, isDone: false };

                    // useMutation 로직 필요
                    mutate(newTodoObj);
                }}>
                <input type="text" value={todoItem} onChange={(e) => setTodoItem(e.target.value)} />
                <button>추가</button>
            </form>
            <ul>
                {todos.map((todo) => {
                    return (
                        <li
                            key={todo.id}
                            style={{
                                display: "flex",
                                alignItems: "center",
                                gap: "10px",
                                backgroundColor: "aliceblue",
                            }}>
                            <h4>{todo.title}</h4>
                            <p>{todo.isDone ? "Done" : "Not Done"}</p>
                        </li>
                    );
                })}
            </ul>
        </div>
    );
};

export default App;

0개의 댓글