React 애플리케이션에서 데이터를 관리하고 처리하기 위한 JavaScript 라이브러리이다. 주로 API 요청과 데이터 캐싱에 사용되며, 서버와의 통신을 비동기적으로 처리하고 데이터를 캐싱하여 애플리케이션의 성능을 향상시킨다.
처음에는 프로젝트 구현에만 집중했기에 단순하게 useEffect 함수 안에서 fetch로 서버 쪽 데이터를 받아와서 사용했다.
✔️ 매번 페이지가 달라질 때마다 각 컴포넌트에서 데이터를 또 받아왔기에 너무 느려졌다. => React query는 새로운 데이터를 요청하지 않고 기존의 캐시된 데이터를 사용하기에 필요하지 않은 경우 효율적인 데이터 요청과 캐싱을 할 수 있고 웹앱이 조금 더 빨라질 수 있을 것을 기대했다.
✔️ 포스트 작성 같은 경우 다른 페이지로 이동이 되기에 서버에 있는 데이터를 다시 받아왔기에 데이터가 갱신이 되었지만 댓글은 같은 페이지에서 일어나서 자동으로 갱신이 되지 않았다. 원래는 댓글을 작성한 후 페이지가 reload를 하도록 함수를 실행시켰지만 효율적이지 않았다 => React query의 경우 데이터가 변경이 되었을 경우 자동으로 갱신을 하기에 효율적으로 데이터 리패칭을 할 수 있을거라 기대했다.
✔️ API 폴더 안에 여러가지 함수로 데이터를 가져왔지만 React Query와 custome hook을 사용해 폴더 구조를 조금 더 단순하고 명확하게 유지할 수 있을거라 기대했다.
useQuery는 서버에서 데이터를 가져오는 용도로 사용되며, 데이터를 수정하는 경우 주로 useMutation을 사용하는 것은 추천한다.
Spport에서 대표적으로 데이터를 읽어오는 것은 피드 정보를 가져오는 것이다. 먼저 여기에 적용해보기로 했다.
대부분의 query들은 custom hook을 사용해서 정리해주기로 결정했다.
useFeedQuery 안에서 정보를 받고 data, isLoading, isError 정보를 넘겨준다.
function useFeedQuery(token) {
const getFeed = async () => {
return await GET_API(token, '/post/feed/?limit=Number?skip=Number');
};
const feedQuery = useQuery({
queryKey: ['feed'],
queryFn: () => getFeed(),
});
return [feedQuery.data, feedQuery.isLoading, feedQuery.isError];
}
도입 전에는 useEffect 안에서 모든 데이터를 받고 있고 isLoad도 같이 설정해주고 있다.
export default function Home(props) {
const [feed, setFeed] = useState([]);
const [isLoad, setIsLoad] = useState(false);
const [token, setToken] = useRecoilState(userToken);
const [filterClick, setFilterClick] = useState(false);
const url = '/post/feed/?limit=1000';
useEffect(() => {
const getData = async () => {
setIsLoad(true);
const data = await GET_API(token, url);
setFeed(data.posts);
setIsLoad(false);
};
getData();
}, []);
return (
<>
<Header main setFilterClick={setFilterClick} />
<FullSection>
{!isLoad && feed.length === 0 && (
<Empty
message='유저 또는 팀을 검색해 팔로우 해보세요!'
btnText='검색하기'
link='/search'
/>
)}
{isLoad ? (
<PostLoader />
) : (
<PostList post={feed} onlyGame={filterClick} isHome />
)}
</FullSection>
<NavBar page='홈' />
</>
);
}
usePost hook에서 데이터를 받는 과정에 관해 모든 것을 처리하고 usePost에서 data, loading, error만 받아왔다.
export default function Home(props) {
const [token] = useRecoilState(userToken);
const [filterClick, setFilterClick] = useState(false);
const [feeds, isFeedLoading, isFeedError] = useFeedQuery(token);
return (
<>
<Header main setFilterClick={setFilterClick} />
<FullSection>
{isFeedError && (
<Empty
message='피드 정보를 가져오는데 실패했습니다.'
btnText='새로고침'
link='/home'
/>
)}
{!isFeedLoading && feeds.posts.length === 0 && (
<Empty
message='유저 또는 팀을 검색해 팔로우 해보세요!'
btnText='검색하기'
link='/search'
/>
)}
{isFeedLoading ? (
<PostLoader />
) : (
<PostList post={feeds.posts} onlyGame={filterClick} isHome />
)}
</FullSection>
<NavBar page='홈' />
</>
);
}
React Query를 도입하기 전에는 홈 페이지에서 다른 페이지로 이동한 후 다시 홈 페이지로 돌아오면 데이터를 다시 받아와서 로딩이 발생했다. 특히 홈 페이지에 상당히 많은 포스트 정보를 가져오는 경우 로딩이 느려서 불편했다.
하지만 React Query를 도입한 후에는 홈 페이지로 다시 돌아오는 경우 데이터를 다시 fetch하지 않고, 이전에 캐시되어 있던 데이터가 그대로 남아있었다. 즉, 이전에 가져온 데이터를 새로 fetch하지 않고 사용하게 되기 때문에 로딩이 발생하지 않았다. 이렇게 React Query는 캐싱 기능을 통해 데이터를 관리하므로 불필요한 네트워크 요청을 줄여주고 사용자 경험을 향상시켰다.
React Query의 도입으로 로딩 속도가 개선되어 빠르고 원활한 홈 페이지 경험을 제공할 수 있게 되어서 매우 만족스러운 결과를 얻었다.
React-query 적용 전 | React-query 적용 후 |
---|---|
![]() | ![]() |
프로필에 갔다가 홈으로 갔을때 다시 데이터를 받아와서 스켈레톤 이미지를 보여준다 | 프로필에 갔다 홈으로 다시 와도 데이터를 다시 받아오지 않아서 포스트 데이터를 전과 같이 보여준다. |
프로필로 갔다가 다시 피드화면으로 가는 것을 개발자 모드의 performance insight를 사용해서 시간을 측정해봤다.
React-query 적용 전 | React-query 적용 후 |
---|---|
![]() ![]() | ![]() ![]() |
프로필에 있을 때 시간: 6.57s | 프로필에 있을 때 시간: 5.461s |
다시 피드화면으로 갔을때 시간: 8.678s | 다시 피드화면으로 갔을때 시간: 6.613s |
총 걸린 시간: 2.108s | 총 걸린 시간: 1.152s |
약 2배 가까이 로딩시간을 줄일 수 있었다.
좋은 정보 얻어갑니다, 감사합니다.