React
React 19 Data Caching (map, React Query, swr)
arkhyeon
2025. 1. 13. 09:41
728x90
반응형
Map 객체를 활용한 데이터 캐싱
요청했던 URL과 데이터를 Map에 저장하므로 동일한 요청은 서버에 다시 호출하지 않고, 저장된 데이터를 반환합니다.
data.js
import { axios } from "./axios.js";
let cache = new Map();
export function fetchData(url) {
if (!cache.has(url)) {
cache.set(url, getData(url));
}
return cache.get(url);
}
async function getData(url) {
if (url.startsWith("/search?q=")) {
return await getSearchResults(url.slice("/search?q=".length));
} else {
throw Error("Not implemented");
}
}
async function getSearchResults(query) {
// Add a fake delay to make waiting noticeable.
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
const a = await axios.get(`/departments/${query}`);
return a.data.departments;
}
- 캐시가 Map에 무한정 쌓이고 오래된 데이터가 계속 유지될 수 있습니다.
- 현재 캐시는 해당 컴포넌트 내에서만 사용됩니다. 여러 컴포넌트에서 캐시를 유지하려면 context나 전역 상태 관리 라이브러리가 필요합니다.
React Query
복잡한 데이터 흐름과 상태 관리가 필요한 대규모 프로젝트 용이
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
const fetchDepartments = async (query) => {
const response = await axios.get(`/departments/${query}`);
return response.data.departments;
};
const DepartmentList = ({ query }) => {
const { data, isLoading, error } = useQuery(
['departments', query],
() => fetchDepartments(query),
{ staleTime: 300000 } // 캐시 데이터 유지 시간
);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading data</p>;
return (
<ul>
{data.map((dept) => (
<li key={dept.id}>{dept.name}</li>
))}
</ul>
);
};
export default DepartmentList;
SWR
소규모 프로젝트나 간단한 데이터 패칭만 필요한 경우 용이
import useSWR from 'swr';
import axios from 'axios';
const fetcher = (url) => axios.get(url).then((res) => res.data.departments);
const DepartmentList = ({ query }) => {
const { data, error, isLoading } = useSWR(`/departments/${query}`, fetcher);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading data</p>;
return (
<ul>
{data.map((dept) => (
<li key={dept.id}>{dept.name}</li>
))}
</ul>
);
};
export default DepartmentList;
여러가지 데이터 캐싱 방법이 있으니 용도에 맞춰 사용하시면 되겠습니다.
Layout
App.jsx
import { Suspense, useState} from "react";
import Department from "./Department.jsx";
function App() {
const [id, setId] = useState(0);
return (
<div className="min-h-screen bg-gray-100 p-6">
<input type="number" value={id} onChange={(e) => setId(Number(e.target.value))} />
<Suspense fallback={<Loading />}>
<div className="mb-6">
<Department id={id} />
</div>
</Suspense>
</div>
);
}
export default App;
function Loading() {
return <h2>🌀 Loading...</h2>;
}
Department.jsx
Department.jsx
//Department.jsx
import { use } from "react";
import { fetchData } from "./data.js";
function Department({ id }) {
const department = use(fetchData(`/search?q=${id}`));
if (id === 0) {
return null;
}
return (
<div>
{department.map((dm) => (
<div className="border border-gray-300 p-4 rounded-md" key={dm.departmentId} >
<h2 className="text-xl font-bold mb-2">이름 : {dm.name}</h2>
<p className="text-gray-600">ID: {dm.departmentId}</p>
<p className="text-gray-600">설명: {dm.description}</p>
<p className="text-gray-600">위치: {dm.location}</p>
</div>
))}
</div>
);
}
export default Department;
728x90
반응형