TanStack Query
사용 전 터미널 열고 설치하기!
yarn add @tanstack/react-query
👩🏻💻 db.json 파일 세팅
{
"todos": [
{
"id": "1715926482394",
"title": "리액트 공부하기",
"isDone": true
},
{
"id": "1715926492887",
"title": "Node.js 공부하기",
"isDone": true
},
{
"id": "1715926495834",
"title": "영화보기",
"isDone": false
}
]
}
: 데이터를 가져오기 위해 사용되는 TanStack Query의 대표적인 훅
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
//import 시키기!
const queryClient = new QueryClient();
createRoot(document.getElementById("root")).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>
);
Context의 Provider 처럼 App 컴포넌트 전체를 감싸주어서 전역에서 사용할 수 있도록 만든다.
⭐️ new QueryClient();
는 한번만 만들어주면 된다.
다른 컴포넌트 가서 똑같이 new QueryClient(); 를 적어버리면 main.jsx에서 만든 QueryClient와 전혀 다른 것이 되어버리므로 주의!! → useQueryClient
사용하면 된다.
import { useQuery } from "@tanstack/react-query";
import axios from "axios"; //json server 데이터 get
function App() {
const fetchTodos = async () => {
const response = await axios.get("http://localhost:4000/todos"); //todos json의 서버 받아오기 (get)
return response.data;
};
const {
data: todos,
isLoading,
isError,
} = useQuery({
queryKey: ["todos"], // 캐싱된 데이터를 불러오기 때문에 DB까지 가서 데이터를 가져오지 않아도 된다 > cost 절감
queryFn: fetchTodos, // queryFn 는 함수를 받아온다 (위에서 별도 작성)
});
if (isLoading) {
return <div>로딩중</div>;
}
if (isError) {
return <div>데이터 호출 중 오류 발생</div>;
}
// console.log("data", data);
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;
: 데이터를 생성, 수정, 삭제하는 등의 작업에 사용되는 훅
import { useMutation, useQuery } from "@tanstack/react-query";
import axios from "axios"; //json server 데이터 get
import { useState } from "react";
function App() {
const [todoItem, setTodoItem] = useState("");
const fetchTodos = async () => {
const response = await axios.get("http://localhost:4000/todos"); //todos json의 서버 받아오기 (get)
return response.data;
};
const addTodo = async (newTodo) => {
await axios.post("http://localhost:4000/todos", newTodo);
};
const {
data: todos,
isLoading,
isError,
} = useQuery({
queryKey: ["todos"],
// 캐싱된 데이터를 불러오기 때문에
//DB까지 가서 데이터를 가져오지 않아도 된다 > cost 절감
queryFn: fetchTodos,
});
const mutation = useMutation({
//mutation 안에 mutate라는 메소드가 있으므로 {mutate} 로 적어도 됨
mutationFn: addTodo,
});
// 생성, 추가, 삭제하는 역할이므로 버튼 onClick에 연결할 예정
if (isLoading) {
return <div>로딩중</div>;
}
if (isError) {
return <div>데이터 호출 중 오류 발생</div>;
}
// console.log("data", data);
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
// const newTodoObj = { title: todoItem, isDone: false };
// useMutation 로직 필요
mutation.mutate({ title: todoItem, isDone: false });
}}
>
<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;
이렇게 POST 로 얻어온 값들은 버튼을 입력하면 데이터를 뿌려준다.
: 특정 쿼리를 무효화하여 데이터를 다시 패칭하게 하는 함수
주로 useMutation
과 함께 사용하여 데이터가 변경된 후 관련 쿼리를 다시 가져오게 해서 최신상태를 유지할 수 있게 한다.
👩🏻💻기존코드에 로직 추가
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import axios from "axios"; //json server 데이터 get
import { useState } from "react";
function App() {
const queryClient = useQueryClient(); // main.jsx에서 만들었던 거 사용
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,
isLoading,
isError,
} = useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
});
const mutation = useMutation({
mutationFn: addTodo,
//데이터 무효화 처리
onSuccess: () => {
queryClient.invalidateQueries(["todos"]);
},
});
if (isLoading) {
return <div>로딩중</div>;
}
if (isError) {
return <div>데이터 호출 중 오류 발생</div>;
}
// console.log("data", data);
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
mutation.mutate({ title: todoItem, isDone: false });
}}
>
<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;
json 데이터가 여러 개라면? (newPost의 객체가 여러개)
const addPost = (newPost) => {
axios.post("http://localhost:4000/posts", {
title: newPost.title, //newPost 안에 있는 title
views: newPost.views, //newPost 안에 있는 views
});
};
<div>
<button onClick={() => {
mutation.mutate({
title: newPost.title
views: newPost.views
});
}}>제출</button>
</div>
queryKey
queryKey
가 더이상 유효하지 않다고 알려주는 것 === invalidateQueries
invalidateQueries
를 쓸 때에는 반드시 queryKey
넣어주기!
탱탱!