기존 상태 관리 라이브러리의 문제점

  • 웹 프레임워크(React, Vue) 그 자체만으로는 전역 상태 관리를 하는것이 불편하다. 그래서 완전 소규모의 웹개발이 아닌이상 개발 시에는 상태 관리 라이브러리 (Redux, Recoil 등등...)을 같이 사용한다.

  • 그런데 상태 관리 라이브러리들의 경우 클라이언트 상태 관리에는 적합하지만, 비동기, 서버 상태를 관리하는데 있어서는 아래와 같은 이유로 적합하지 않다.

    • 데이터는 개발자가 통제할 수 없는 위치에 저장되고
    • fecth, update를 위한 API가 필요하며
    • 다른 개발자, 또는 다른 사용자에 의해 언제든지 데이터가 변경될 수 있으며
    • 관리에 신경쓰지 않으면 서버의 데이터가 먼저 업데이트되고, 클라이언트의 데이터는 구식이 될 수 있다.
  • 가령 서버에서 현재 로그인한 유저의 데이터를 가져와 저장하는 로직을 Recoil을 사용해 구현해본다 해보자.

export const currentUserID = atom<string>({
	key: "currentUserID",
  	default: "".
});

export const getCurrentUserInfo = selector({
	key: "getCurrentUserInfo",
  	get: async({get}) => {
      const id = get(currentUserID);
      if (!id) return {};
      try {
        return await (await fetch(`https://somepage.com/users/${id}`)).json();
      } catch(error) {
        throw Error("Network Error");
      }
    }
});
  • 서버에서 비동기 데이터를 가져와야 하기 때문에 사용하는 곳에서 예외 처리에 신경써줘야 하며, 따로 refresh를 구현하지 않을 경우 서버의 정보가 바뀌었음에도 불구하고 캐싱된 결과를 반환해 서버의 데이터와 다른 결과를 반환할 위험성을 가지고 있다.
  • recoil을 사용한 경우에도 간단한 서비스라면 위의 코드와 같이 몇줄의 코드만으로도 충분하겠지만, 캐싱, 데이터 갱신등의 문제를 고려하게 되면 코드가 매우 길어지게 된다.

React-Query

  • 기존 상태 관리 라이브러리가 가진 단점을 해결하기 위해 서버와 연동되는 데이터 상태 관리를 도와주는 라이브러리들이 출시되었다.
  • React-Query 역시 이 중 하나로, 다양한 기능을 가져 개발자들에게 많은 사랑을 받고있다.
  • 공식 문서에 따르면 아래와 같은 Reqct-Query 사용으로 아래와 같은 문제들을 해결해줄 수 있다 언급하고 있다.
    • 캐싱
    • 동일한 요청의 중복 방지
    • 데이터의 "out of date" 확인 및 갱신
    • 데이터 업데이트, lazy loading, 페이지네이션 등에서의 성능 최적화
    • 가비지 컬렉션
  • 그렇다면 앞선 코드를 react-query를 사용해 다시 작성해보자.
// 토큰이 쿠키에 저장되어 있다 해보자.
const { status, data: currentUser } = useQuery({
	queryKey: ["getCurrentUserInfo"],
  	queryFn: () => await (await fetch(`https://somepage.com/currentuser/`)).json(),
}); 
  • Recoil을 사용한 경우도 (컴포넌트 로직만을 따지면) 상당히 짧은 코드였지만, react-query를 사용한 경우 단 4줄만으로 데이터 관리와, 예외 처리까지 전부 해결이 가능하다!
  • 서버 상태 관리를 react-query로 관리하게 될 경우 로컬로 관리해야 할 상태는 웹사이트 설정, 테마 등의 일부분만이 남게 되고, 이는 상태 관리 라이브러리 사용없이 context api등의 자체 기능으로 충분히 관리가 가능하게 된다.
    • 만약 관리해야할 로컬 상태가 많다면 여전히 상태 관리라이브러리를 사용해야 하지만, react-query와 동시 사용이 가능하기 때문데 각각을 따로 관리해주면 된다.
  • 구체적으로 공식문서에서는 아래와 같이 기술적인 장점을 제시하고 있다.
    • 여러줄의 복잡하고 잘못 작성했을 수 있는 코드를 몇줄로 간소화
    • 서버 데이터에 처리에 대한 부담없이 기능 구축 가능
    • 애플리케이션 성능 향상
    • 데이터, 메모리 절약 가능

사용 예시

  • 공식 문서에서 간단한 예시를 가지고 왔다.
import {
  QueryClient,
  QueryClientProvider,
  useQuery,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
    </QueryClientProvider>
  )
}

function Example() {
  const { isLoading, error, data } = useQuery({
    queryKey: ['repoData'],
    queryFn: () =>
      fetch('https://api.github.com/repos/TanStack/query').then(
        (res) => res.json(),
      ),
  })

  if (isLoading) return 'Loading...'

  if (error) return 'An error has occurred: ' + error.message

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      <strong>👀 {data.subscribers_count}</strong>{' '}
      <strong>{data.stargazers_count}</strong>{' '}
      <strong>🍴 {data.forks_count}</strong>
    </div>
  )
}

출처:
https://tanstack.com/query/latest/docs/react/overview

profile
냐아아아아아아아아앙

2개의 댓글

comment-user-thumbnail
2023년 8월 18일

많은 것을 배웠습니다, 감사합니다.

1개의 답글
Powered by GraphCDN, the GraphQL CDN