react-query

우현민·2021년 9월 29일
6

글을 작성하기에 앞서, 저는 react-query를 올해 3월부터 시작해서 회사 직무에서 단 반년밖에 사용해보지 않았다는 부분을 강조드립니다.

react-query란?

react-query는 tanstack에서 만든 서버사이드 상태 관리 라이브러리입니다. 서버사이드 상태가 뭘까요? 이들은 다음과 같이 주장합니다.

server state는 client state와 많은 부분에서 차이가 있습니다. 기존의 훌륭한 상태 관리 라이브러리들은 client state 관리에 초점을 맞추고 있기 때문에 server state 관리에는 적합하지 않습니다.

그러니까 이들은 지금껏 대중적으로 사용되는 redux-sagaredux-thunk 등이 "서버 데이터를 다루는 것" 에 적합하지 않다고 주장하며, 서버 데이터를 다루기 위한 아예 새로운 메커니즘을 제안합니다.

이들의 주장을 조금 더 자세히 알아보겠습니다.

우선, 클라이언트 상태의 대표적인 예시는 다음과 같습니다.

  • 모달이 열려 있는지
  • (JWT) 토큰값을 가지고 있는지
  • (리액트) 입력중인 값의 상태

서버 상태의 대표적인 예시는 다음과 같습니다.

  • 서버에서 가져온 데이터

서버 상태는 클라이언트 상태와 다음 부분에서 차이가 있습니다.

  • 내 클라이언트에 귀속된 데이터가 아니므로, 최신화에 대한 고민이 있음
  • 데이터 캐싱 (아마도 가장 큰 부분)
  • 등등

react-query의 목표는 이런 부분들에 대한 완벽한 솔루션을 제공하겠다는 것입니다. server state가 가지는 많은 차이점들을 대응할 수 있도록, 잘 정리된 내장 함수들과 훌륭한 캐싱 기능을 제공합니다.

이런 깔끔하고 명확한 컨셉을 바탕으로, 나온 지 얼마나 됐다고 벌써 리액트 비동기 생태계를 지배하던 redux-saga의 자리를 강력하게 위협하고 있습니다.

출처 npm-trends



react-query 사용법 (useQuery 훅)

정확히는, 이들은 api 통신 로직 자체를 다루지는 않습니다. 이들이 제공하는 정확한 기능은 "비동기 함수와 그것의 리턴 값"에 대한 데이터 캐싱 등의 기능이고, 실제로 Promise를 리턴하는 axios.get('https://...') 등의 코드는 개발자가 직접 구현해야 합니다.

이들은 각각의 데이터에 query라는 이름을 붙입니다. 그리고 각각의 query마다 unique한 key값을 제공하기를 요구합니다. 이 key값을 통해 해당하는 함수와 데이터를 식별하고, 그 데이터를 알아서 잘 처리해주겠다는 거죠. 이를 queryKey라고 합니다. 사용법에 대한 자세한 정보는 문서에서 확인할 수 있습니다.

또한 각각의 query에는 상술했다시피 매치되는 비동기 함수 queryFn이 있습니다. 이 queryFn은 실제로 axios 등을 이용하여 비동기 로직을 수행하고, 결과를 리턴합니다.

그리고 이들 query의 값, 상태 등등은 queryClient에 저장되고, QueryClientProvider를 통해 제공되며 useQuery 훅을 통해 접근할 수 있습니다. 물론 queryClient에 직접 접근할 수도 있습니다.

너무 이론 이야기만 하면 재미없으니 코드를 볼까요? 3초에 한번씩 투두 목록을 폴링하는 다음 코드를 보겠습니다.

const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState();

const fetchData = async () => {
  try {
    const response = await axios.get('https://jsonplaceholder.typicode.com/todos');
    setData(response.data);
  } catch (err) {
    console.error(err);
  }
};

useEffect(() => {
  const tick = setInterval(fetchData, 3000);
  return () => clearInterval(tick);
}, []);

코드도 복잡하고, 가독성도 좋지 않습니다. 여러 state들을 반복적으로 사용하게 되고, 비동기 로직에 대한 추상화가 잘 이루어지지 않습니다. 지금은 컴포넌트 내의 state로 처리하고 있지만 redux-saga 등에서 이를 처리하려 하면 더 복잡해질 것 같습니다.

react-query 로 구현한다면 어떨까요?

const queryKey = ; // 당연히 보통 이렇게 변수 따로 안 만들고 useQuery 안에 바로 적습니다
const queryFn = ;

const { isLoading, data } = useQuery(
  'todos', 
  async () => {
    const response = await axios.get('https://jsonplaceholder.typicode.com/todos');
    return response.data;
  },
  {
    refetchInterval: 3000,
  }
);

훨씬 간결한 코드 안에 복잡한 비동기 관련 로직들을 다 담을 수 있죠? useQuery 훅은 여기에 더해 isFetching, isError, refetch 등의 다양한 변수와 함수들을 제공해 줍니다.




react-query의 기능

우선 앞서 말씀드렸다시피, 클라이언트 상태인 state를 직접 이용해 구현하기에는 귀찮고 + 의미도 별로고 + 복잡한 비동기 로직들을 전부 알아서 챙겨주는 라이브러리입니다. 폴링, 로딩, 캐싱 등 수많은 기능이 라이브러리에 포함되어 있습니다. "비동기 작업과 관련된" 정말 대부분의 귀찮은 작업들을 모두 간단한 코드 몇 줄로 안전하게 처리할 수 있고, 캐싱 덕에 성능 또한 우수합니다!

react-query의 단점

이렇듯 장점이 많지만 아쉽게도, 이 라이브러리는 나온 지 그리 오래되지 않았고, 아무래도 그동안 리액트 시장을 redux-saga가 지배하고 있었다 보니 아직은 그들에 비해 커뮤니티 규모가 그리 크지 않습니다. 때문에 queryKey에 대한 best practice 등이 잘 정립되지도 않은 것 같습니다.

총평

우선 저는 한번 이 라이브러리에 맛을 들인 이후로, 규모가 너무 작거나 너무 레거시여서 건드리지 못하겠는 코드가 아닌 이상 모든 프로젝트에 이 라이브러리를 적용하고 있습니다. 사용해보고 단점이 전혀 없다고 말하지는 못하지만, 리액트 생태계에 새로운 패러다임을 제시하고 있다고 보일 정도로 무섭게 성장중인 라이브러리입니다!

profile
프론트엔드 개발자입니다

1개의 댓글

comment-user-thumbnail
2023년 11월 28일

Larger companies can effectively work with several excellent freelancers in one location by using this method. https://spacebar-clicker.net/

답글 달기