Redux에서 React-Query로 이전

김영재·2024년 3월 31일
0
post-thumbnail

상태란? REDUX???MOBX???

주어진 시간에 대해 시스템을 나타내는 것 → 언제든 변경될 수 있음. 문자열, 배열, 객체 등의 형태로 프로그램에 저장된 데이터이다.
개발자 입장에선 쉽게 생각해 오너십가지고 관리해야하는 데이터라고 할 수 있다.
모던 웹 프론트엔드 개발에서 프로덕 규모가 커지면서 더많은 상태가 생기고 결론적으로 관리해야할 상태가 많아짐
react에서 만약 최상단에 함수, 상태값들을 정의하고 props로 넘겨받으면 동작하는데는 문제가 없지만 props drilling이 발생하고 상태값 또한 많아지면 관리는 더욱 힘들어집니다.
또한 재사용 가능한 컴퍼넌트를 생성하는걸 중요시 생각하는 개발자 입장에서 과도한props로 넘겨받는 인자들은 재사용성을 떨어뜨립니다.
우린 이런 문제 해결을 위해 redux를 사용했었습니다.

Redux

리덕스 동작방식은 상태변화가 필요할때 action을 발생시킵니다. 이때 액션은 하나의 객체로 이루어져있습니다.
이때 액션생성함수(action creator)를 통해 액션을 생성하고 단순히 인자를 받아 액션객체형태로 만들어줍니다.
리듀서는 현재 상태와 새롭게 전달받은 액션 두가지를 파라미터로 받고 현재의 상태와 새로운 액션을 참조하여 새로운 상태값을 반환해주는 것을 리듀서라고 합니다.
그리고 이를 다시 store에 저장합니다.이런상황에서 서버상태관리를 위해 서드파티 라이브러리 saga를 도입했습니다. 그런데 아래와 같은 문제가 발생했습니다.

  • api통신 코드가 너무 많아짐
  • 에러처리
  • 반복적인 구조로 계속 이루어지는 API통신코드
  • 작은 기능이라도 리덕스로 구현하는 순간 상당한 보일러 플레이트 코드(액션 타입, 액션 생성함수, 리듀서...)

서버 상태의 특징 (React-query 공식문서)

  • 소유되지 않는 원격의 공간에서 관리되고 유지됨
  • fetching, update에 비동기 API가 필요
  • 다른 사람과 공유되는 것으로 사용자가 모르는 사이 변경 가능
  • 신경 안쓰면 잠재적으로 out of date가 될 가능성을 가지고있음

Client state vs. Server state

Client State (Ownership이 Client에)

  • client에서 소유하며 온전히 제어가 가능함
  • 초기값 설정이나 조작에 제약사항이 없음
  • 다른 사람들과 공유되지 않으며 Client내에서 UI/UX흐름이나 사용자 인터렉션에 따라 변할 수 있음
  • 항상 Client내에서 최신상태 유지

Server State (Ownership이 Server에)

  • 클라이언트에서 제어하거나 소유되지 않은 원격의 공간에서 관리되고 유지
  • fetching/updating에 비동기 API가 필요함
  • 다른 사람들과 공유되는 것으로 사용자가 모르는 사이 변경 가능
  • 신경쓰지 않으면 잠재적으로out of date가 될 가능성을 지님

React-Query

React Query is often described as the missing data-fetching library for React,but in more technical terms, it makes fetching, caching, synchronizing andupdating server state in your React applications a breeze
React 애플리케이션에서 서버 상태를 가져오고, 캐싱하고, 동기화하고 업데이트 하는것을 매우 쉽게 만들어준다는 뜻이다.
아래의 코드는 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>
  )
}

여기서 repoData는 쿼리 키값이고, key-value매핑 구조를 가진다.
useQuery는 Hook으로 수행되는 Query요청은 HTTP METHOD GET 요청과 같이 서버에 저장되어있는 상태를 불러와 사용할 때 사용합니다.
Mutation은 query와 다르게 데이터 업데이트 시 사용합니다. CRUD에서 useQuer가 Read였다면 나머지 Create,update,delete는 mutation으로 사용합니다. useMutation은 Hook으로 요청시 HTTP METHOD POST,PUT,DELETE요청과 같이 서버에 side Effect를 발생시켜 서버의 상태를 변경할 떄 사용합니다.

// hooks/queries/inquiry.ts
import { useQuery } from 'react-query';
import * as API from 'api';
export const useGetInquiryList = (query: any, options: any) =>
  useQuery('useGetInquiryList', () => API.getInquiriesList(qu
};

여기서 CRUD의 read즉 get메서드를 호출하기 위해 useQuery를 활용해 getInqurires란 API를 호출한다.
여기서 key값 useGetInquiryList에 response가 value로 매핑되게 될 것이다.
해당 훅스를 필요한 UI컴퍼넌트에서 호출해보자.

const getInquiryList = useGetInquiryList(query, {
    onSuccess: (data: any) => {
      console.log(data);
    },
    onError: (error: any) => {
      alert(error.message);
	} 
});

따로 useEffect를 사용하지 않아도 default로 컴퍼넌트가 mount시 해당 함수가 실행될 것이다.
또한 response에서 성공시, 에러시 핸들링을 간단하게 처리할 수있다.
그럼 하위 컴퍼넌트에서 상태값을 어떻게 꺼내 사용할까?

import { useQueryClient } from 'react-query';
const queryClient = useQueryClient();
const testList = queryClient.getQueryData('useGetInquiryList')
console.log('ui compo level', testList);

이전에 useGetInquiryList라는 키값에 response값을 매핑했으니 해당 키값을 통해 접근해 값을 받아올 수있다.

어디서 상태관리를 할까?

Context Api에 있습니다. 실제 react-query라이브러리 코드를 보면 queryClient내부적으로 Context를 사용합니다

도입시 기대되는 결과값

클라이언트 상태관리를 하는데 있어 redux, zustand, recoil, mobx어떤 클라이언트 상태 관리 라이브러리를 사용해도 클라이언트 상태관리들만 남아 목적에 맞게 심플하다.

서버 상태값들은 react-query를 통해 간단하지만 아주 직관적으로 처리가 가능하다.
무엇보다 서버 상태와 클라이언트 상태 관리를 확실히 분리하여 사용할 수있다는 장점이 있다.

해결 못한것

수많은 useQuery의 키값을 어떻게 관리할지 고민이다. ui컴퍼넌트 내부에서 useQuery를 이용해 해당 키값에 밸류를 매핑해서 사용하는건 좋다.
하지만 이렇게 컴퍼넌트 레벨에서 해당 쿼리를 마구 생성하면 점점 프로젝트가 커지면 저 방대한 양의 키값을 어떻게 처리할까...?

profile
[ frontend-developer ]

0개의 댓글