Redux나 Recoil과 같은 클라이언트 측 상태 관리 라이브러리와는 다르게
React-Query가 주로 서버 상태를 관리하며, 데이터 fetching, caching, synchronization, 그리고 업데이트 작업을 효율적으로 처리하기 때문에 React-Query를 사용하게 되었다.
기존 방식 (서버에서 직접 데이터 가져오기)
import React, { useEffect, useState } from "react";
import { View, Text } from "react-native";
import axios from "axios";
const Test = () => {
const [data, setData] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const getData = async () => {
try {
const response = await axios.get("https://example.com/data");
if (!response.data) {
throw new Error("No data");
}
return response.data;
} catch (error) {
console.error("Error fetching data:", error);
}
};
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
const dataList = await getData();
setData(dataList);
} catch (error) {
setError(error.message || "error");
} finally {
setIsLoading(false);
}
};
fetchData();
}, []);
if (isLoading) return <Text>Loading...</Text>;
if (error) return <Text>Error: {error}</Text>;
return (
<View>
{data.map((item, index) => (
<Text key={index}>{item}</Text>
))}
</View>
);
};
export default Test;
React-Query 사용
import React from "react";
import { View, Text } from "react-native";
import axios from "axios";
import { useQuery } from "react-query";
const Test = () => {
const { data, isLoading, error } = useQuery("testData", async () => {
const response = await axios.get("https://example.com/data");
return response.data;
});
if (isLoading) return <Text>Loading...</Text>;
if (error) return <Text>Error: {error.message}</Text>;
return (
<View>
{data.map((item: string, index: number) => (
<Text key={index}>{item}</Text>
))}
</View>
);
};
export default Test;
두 코드를 비교해봤을 때, 확실히 React-Query를 사용한 코드가 간결하다.
비동기 데이터 fetching, 에러 핸들링을 위해 별도의 상태 및 함수를 필요로 하지 않고
useQuery훅을 사용해서 한 곳에서 fetching과 관련된 모든 로직을 처리 할 수 있다.
중복된 요청을 방지하고, 새로고침이 필요한 경우 캐시된 데이터를 사용하여 네트워크 요청을 최소화 한다.
staletime, cachetime 이란?
✔️ staleTime
staletime이란 데이터가 fresh -> stale 상태로 변경되는데 걸리는 시간을 말한다.
설정한 staleTime이 지나기 전까지 데이터의 상태는 fresh이며, staleTime이 지난 데이터는 stale한 데이터로 간주하게 된다.
즉, staleTime fresh 상태 동안에는 데이터가 캐시에 있고,
staletime이 지나 stale 상태가 되어도 데이터는 즉시 삭제되지 않는다.
사용자가 해당 데이터를 요청하면 백그라운드에서 새로운 데이터를 요청하는 동안 임시적으로 stale상태의 캐시된 데이터를 보여줄 수 있다.
staleTime은 밀리초 단위로 설정되며, 기본값은 0 (데이터는 항상 만료 상태이므로, 서버에서 다시 가져와야 한다고 가정해서 기본값은 0이다.)
cacheTime은 밀리초 단위로 설정되며, 기본값은 5분이다.(300000 밀리초)
staleTime은, cacheTime 차이점?
staleTime과 cacheTime의 차이점은 valid, invalid이다.
staleTime은 데이터가 언제까지 fresh하게 유지되는지,
cacheTime은 데이터가 캐시에 언제까지 남아있을지 결정한다.
예제)
import { useQuery } from 'react-query';
const { data, isLoading, error } = useQuery('posts', fetchPosts, {
staleTime: 10000, // 10초 이내에는 캐시된 결과를 사용함
cacheTime: 600000, // 10분 동안 데이터가 캐시됨
});
에러 핸들링을 위한 별도의 코드를 작성할 필요 없이 처리 가능하다.
상태마다 작성해줘야 하는 useEffect를 제거할 수 있다!
react-query가 내장된 기능으로 관련된 로직들을 전부 처리해주니
유지 보수하기에도 좋고, 획일화 된 방식으로 코드로 작성할 수 있어서 좋다.
invalidateQueries는 데이터가 오래되었다고 판단되면,
캐시된 데이터를 무효화하여 자동으로 데이터를 다시 가져오는 기능이다.
이 기능은 캐시된 데이터의 유효성을 유지하고, 최신 데이터를 유지하는데 도움이 된다.
예를 들어, 실시간으로 업데이트 되는 데이터를 보여주는 경우, 데이터는 항상 최신의 상태로 유지되어야 한다.
사용자가 페이지를 새로 고치거나 새로운 데이터를 요청하지 않아도 항상 최신 정보를 제공해야 한다.
데이터가 오래되었다고 판단되면 캐시된 데이터를 자동으로 무효화하고 새로운 데이터를 가져오는 기능은
데이터 관리를 효율적으로 작업할 수 있도록 도와준다.
기존에는 스크롤 이벤트를 감지하면 데이터를 서버에서 가져와서 화면에 추가하는 방식으로 구현하였지만,
React-Query에 있는 useInfiniteQuery 훅을 사용하면 쉽게 처리할 수 있다.
이 훅을 사용하면 페이지별로 데이터를 가져오는 API endpoint를 호출하고,
각 페이지의 데이터를 캐시에 저장하여 효율적으로 관리할 수 있다.
사용자가 스크롤을 하면 추가 페이지의 데이터를 요청하고 화면에 표시하는 과정을 자동으로 처리한다.
기존 방식 (서버에서 직접 데이터 가져오기)
import React, { useEffect, useState } from "react";
import { getPosts, createPost } from "./api";
const MyComponent = () => {
const [posts, setPosts] = useState([]);
useEffect(() => {
const fetchPosts = async () => {
const fetchedPosts = await getPosts();
setPosts(fetchedPosts);
};
fetchPosts();
}, []);
const handleCreatePost = async (newPost) => {
await createPost(newPost);
const fetchedPosts = await getPosts();
setPosts(fetchedPosts);
};
return (
// 컴포넌트 렌더링
);
};
export default MyComponent;
React-Query 사용
import React from "react";
import { useQuery, useMutation } from "react-query";
import { getPosts, createPost } from "./api";
const MyComponent = () => {
const { data: posts } = useQuery("posts", getPosts);
const createPostMutation = useMutation(createPost, {
onSuccess: () => {
queryClient.invalidateQueries("posts");
},
});
const handleCreatePost = async (newPost) => {
await createPostMutation.mutateAsync(newPost);
};
return (
// 컴포넌트 렌더링
);
};
export default MyComponent;
데이터를 가져오는 API 요청을 실행한 후에 해당 데이터를 변경하면, React Query가 자동으로 새로운 데이터를 가져오도록 갱신한다.
예를 들어, 게시판의 글 목록을 가져오는 API를 호출한 후에 새로운 글을 작성하면,
React Query는 자동으로 해당 게시판의 글 목록을 다시 가져오게 된다.
따라서 새로운 데이터가 추가되거나 변경될 때 즉시 최신 상태로 유지되도록 하는 데 도움이 된다.