React Query Custom Hook 적용하기 (useQuery 편)

HYERI ·2023년 7월 30일
1

Spport 프로젝트

목록 보기
1/3
post-thumbnail

React Query란?

React 애플리케이션에서 데이터를 관리하고 처리하기 위한 JavaScript 라이브러리이다. 주로 API 요청과 데이터 캐싱에 사용되며, 서버와의 통신을 비동기적으로 처리하고 데이터를 캐싱하여 애플리케이션의 성능을 향상시킨다.

주요기능

  1. 데이터 요청과 캐싱: 서버로부터 데이터를 가져와 캐시하여, 필요한 경우에 새로운 데이터를 요청하지 않고 기존의 캐시된 데이터를 사용한다.
  2. 비동기 처리: 비동기적인 데이터 요청을 처리하여 애플리케이션이 멈추거나 느려지는 현상을 방지한다.
  3. 자동 캐시 유효성 관리: 데이터의 변경을 감지하여 캐시를 자동으로 갱신하고, 불필요한 데이터 요청을 줄여준다.
  4. 오류 처리: 서버 요청 중 발생하는 오류를 쉽게 처리하고 오류 상태를 관리한다.
  5. 데이터 리패칭: 데이터의 변경에 따라 자동으로 캐시를 갱신하거나, 사용자의 요청에 따라 캐시를 다시 가져오는 기능을 제공한다.

React Query 도입 이유

처음에는 프로젝트 구현에만 집중했기에 단순하게 useEffect 함수 안에서 fetch로 서버 쪽 데이터를 받아와서 사용했다.

✔️ 매번 페이지가 달라질 때마다 각 컴포넌트에서 데이터를 또 받아왔기에 너무 느려졌다. => React query는 새로운 데이터를 요청하지 않고 기존의 캐시된 데이터를 사용하기에 필요하지 않은 경우 효율적인 데이터 요청과 캐싱을 할 수 있고 웹앱이 조금 더 빨라질 수 있을 것을 기대했다.

✔️ 포스트 작성 같은 경우 다른 페이지로 이동이 되기에 서버에 있는 데이터를 다시 받아왔기에 데이터가 갱신이 되었지만 댓글은 같은 페이지에서 일어나서 자동으로 갱신이 되지 않았다. 원래는 댓글을 작성한 후 페이지가 reload를 하도록 함수를 실행시켰지만 효율적이지 않았다 => React query의 경우 데이터가 변경이 되었을 경우 자동으로 갱신을 하기에 효율적으로 데이터 리패칭을 할 수 있을거라 기대했다.

✔️ API 폴더 안에 여러가지 함수로 데이터를 가져왔지만 React Query와 custome hook을 사용해 폴더 구조를 조금 더 단순하고 명확하게 유지할 수 있을거라 기대했다.


useQuery 적용

useQuery는 서버에서 데이터를 가져오는 용도로 사용되며, 데이터를 수정하는 경우 주로 useMutation을 사용하는 것은 추천한다.

Spport에서 대표적으로 데이터를 읽어오는 것은 피드 정보를 가져오는 것이다. 먼저 여기에 적용해보기로 했다.

hook: usePost

대부분의 query들은 custom hook을 사용해서 정리해주기로 결정했다.

useFeedQuery

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];
}

page: Home (query 도입 전)

도입 전에는 useEffect 안에서 모든 데이터를 받고 있고 isLoad도 같이 설정해주고 있다.

  • 비동기 처리때문에 useEffect 안에 또 다른 함수를 생성하는 것도 조금 코드가 명확해보이지 않았다
  • setIsLoad를 두 번이나 설정해주어야하는 부분도 마음에 들지 않았다.
  • 여기서는 나오지 않았지만 api와 util 폴더 안에서 따로 API를 받는 함수도 정의해주어서 상당히 함수와 파일의 구분이 모호했다.
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='홈' />
    </>
  );
}

page: Home (query 도입 후)

usePost hook에서 데이터를 받는 과정에 관해 모든 것을 처리하고 usePost에서 data, loading, error만 받아왔다.

  • useEffect를 사용하지 않아도 되서 home 파일이 간결해졌다.
  • usePost에서 관련 API 함수들을 사용하게 되어 api나 util 안에 있는 관련 함수들을 정리할 수 있게 되었다.
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배 가까이 로딩시간을 줄일 수 있었다.

1개의 댓글

comment-user-thumbnail
2023년 7월 30일

좋은 정보 얻어갑니다, 감사합니다.

답글 달기