📌 TanStack Query
TanStack Query는 React Query라는 이름으로 시작했지만, v4 부터 React 외에도 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되며 TanStack Query라는 이름으로 변경되었다.
TanStack Query는 React에서 서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 보다 쉽게 다룰 수 있도록 도와주는 라이브러리이다. 클라이언트 상태와 서버 상태를 명확히 구분하기 위해 만들어졌다.
기존의 useState나 Redux Thunk 등을 사용한 비동기 데이터 요청 방법의 복잡성을 해결하고, 서버 상태 관리를 좀 더 용이하게 하기 위해 TanStack Query가 등장하게 되었다.
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await axios.get(API_URL);
setData(response.data);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
const initialState = {
isLoading: false,
error: null,
itemList: [],
selectedItems: [],
};
const itemSlice = createSlice({
name: 'item',
initialState,
reducers: {
startLoading: (state) => {
state.isLoading = true;
},
hasError: (state, action) => {
state.isLoading = false;
state.error = action.payload;
},
getItemListSuccess: (state, action) => {
state.isLoading = false;
state.itemList = action.payload;
},
addToSelectedItems: (state, action) => {
// ... existing code ...
},
removeFromSelectedItems: (state, action) => {
// ... existing code ...
},
},
});
export const {
startLoading,
hasError,
getItemListSuccess,
addToSelectedItems,
removeFromSelectedItems,
} = itemSlice.actions;
// ------------------------------------------------------------
export const fetchItemList = () => async (dispatch) => {
dispatch(startLoading());
try {
const response = await axios.get('/api/items');
dispatch(getItemListSuccess(response.data.items));
} catch (error) {
dispatch(hasError(error.message));
}
};
export default itemSlice.reducer;
npm i @tanstack/react-query
yarn add @tanstack/react-query
// main.tsx
import { createRoot } from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import "./index.css";
const queryClient = new QueryClient();
createRoot(document.getElementById("root")!).render(
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
);
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
const App = () => {
const fetchData = async () => {
const response = await axios.get(API_URL);
return response?.data;
};
const { data, isLoading, isError, error } = useQuery({
queryKey: ["data"],
queryFn: fetchData,
});
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
return (
<div>
<h3>TanStack Query</h3>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</div>
);
};
export default App;
import { useMutation, useQuery } from "@tanstack/react-query";
import axios from "axios";
import { useState } from "react";
const App = () => {
const [item, setItem] = useState("");
const fetchData = async () => {
//...
};
const { data, isLoading, isError, error } = useQuery({
queryKey: ["data"],
queryFn: fetchData,
});
const addItem = async (newItem) => {
await axios.post(API_URL, newItem);
};
const { mutate } = useMutation({
mutationFn: addItem,
onMutate() {
/* ... */
},
onSuccess(data) {
console.log(data);
},
onError(err) {
console.log(err);
},
onSettled() {
/* ... */
},
});
return (
<div>
<h3>TanStack Query</h3>
<form
onSubmit={(e) => {
e.preventDefault();
const newItemObj = { title: item, isDone: false };
mutate(newItemObj);
}}
>
<input
type="text"
value={item}
onChange={(e) => setItem(e.target.value)}
/>
<button>추가</button>
</form>
<ul>
{data?.map((entry) => (
<li key={entry.id}>{entry.title}</li>
))}
</ul>
</div>
);
};
export default App;
const { mutate } = useMutation({
mutationFn: addItem,
onSuccess: () => {
queryClient.invalidateQueries(["data"]);
},
});