Front-End(feat. React)에서 서버 상태 관리

하태현·2022년 6월 20일
0

Redux, Mobx같은 전역 상태 관리 라이브러리를 많이 사용하고 있었을 것이다. 해당 라이브러리들은 비동기 작업을 하기 위해선 추가적으로 작성해야하는 코드 양이 늘어난다.
배보다 배꼽이 더 큰 상황이 되는 것이다.

예로 redux-saga 코드를 작성해 보았다.

import { delay, put, takeEvery, takeLatest } from 'redux-saga/effects';

// 액션 타입
const INCREASE = 'INCREASE';
const DECREASE = 'DECREASE';
const INCREASE_ASYNC = 'INCREASE_ASYNC';
const DECREASE_ASYNC = 'DECREASE_ASYNC';

// 액션 생성 함수
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
export const increaseAsync = () => ({ type: INCREASE_ASYNC });
export const decreaseAsync = () => ({ type: DECREASE_ASYNC });

function* increaseSaga() {
  yield delay(1000); // 1초를 기다립니다.
  yield put(increase()); // put은 특정 액션을 디스패치 해줍니다.
}
function* decreaseSaga() {
  yield delay(1000); // 1초를 기다립니다.
  yield put(decrease()); // put은 특정 액션을 디스패치 해줍니다.
}

export function* counterSaga() {
  yield takeEvery(INCREASE_ASYNC, increaseSaga); // 모든 INCREASE_ASYNC 액션을 처리
  yield takeLatest(DECREASE_ASYNC, decreaseSaga); // 가장 마지막으로 디스패치된 DECREASE_ASYNC 액션만을 처리
}

// 초깃값 (상태가 객체가 아니라 그냥 숫자여도 상관 없습니다.)
const initialState = 0;

export default function counter(state = initialState, action) {
  switch (action.type) {
    case INCREASE:
      return state + 1;
    case DECREASE:
      return state - 1;
    default:
      return state;
  }
}

React-Query

React Query는 종종 React에 대한 누락된 데이터 가져오기 라이브러리로 설명되지만 보다 기술적인 용어로 말하면 React 애플리케이션에서 서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 쉽게 만듭니다.
출처: react-query - overview

React-query는 서버 상태를 가져오는 전문 라이브러리 인것이다.

React-Query측의 Motivation을 읽어 보면

기본적으로 React 애플리케이션 에는 구성 요소에서 데이터를 가져오거나 업데이트하는 독창적인 방법이 제공 되지 않으므로 개발자는 결국 데이터를 가져오는 고유한 방법을 구축하게 됩니다. 이는 일반적으로 React 후크를 사용하여 구성 요소 기반 상태와 효과를 함께 엮거나 더 범용 상태 관리 라이브러리를 사용하여 앱 전체에 비동기 데이터를 저장하고 제공하는 것을 의미합니다.
대부분의 기존 상태 관리 라이브러리는 클라이언트 상태 작업에 적합하지만 비동기 또는 서버 상태 작업에는 그다지 좋지 않습니다. 이것은 서버 상태가 완전히 다르기 때문 입니다.

위에서 Redux-saga로 비동기 상태를 작성하며 느꼈던 문제점에 대해서 설명 하고 있다.

서버 상태란

  • 제어하거나 소유하지 않은 위치에 원격으로 유지된다.
  • Fetching, Updating을 위한 비동기 API필요
  • 공유 소유권을 의미하며 사용자 모르게 다른 사람이 변경할 수 있다.
  • 주의하지 않으면 애플리케이션이 잠재적으로 "오래된" 상태가 될 수 있다.

예를들어 나의 주소를 보여주는 화면을 A와 B가 보고 있는데 A가 주소를 수정했다면 B는 해당 데이터(주소)에 대한 refetching을 하지 않는다면 영원히 이전의 주소로 보이게 될것이다. 이렇게 기존의 전역상태(클라이언트 상태)만으론 서버 데이터와 동기화가 되지않는다. 이를 해결하기 위한 또 다른 비용이 추가되는 것이다.

Example

 import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
 
 const queryClient = new QueryClient()
 
 export default function App() {
   return (
     <QueryClientProvider client={queryClient}>
       <Example />
     </QueryClientProvider>
   )
 }
 
 function Example() {
   // 한 줄로 서버 상태를 선언할 수 있다.
   const { isLoading, error, data } = useQuery('repoData', () =>
     fetch('https://api.github.com/repos/tannerlinsley/react-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>
   )
 }

redux-saga를 사용했을때의 수십줄의 코드를 한 줄의 코드로 간단하게 사용할 수 있다.

Refference

velopert's blog - redux-saga
react-query - overview

profile
왜?를 생각하며 개발하기, 다양한 프로젝트를 경험하는 것 또한 중요하지만 내가 사용하는 기술이 어떤 배경과 이유에서 만들어진 건지, 코드를 작성할 때에도 이게 최선의 방법인지를 끊임없이 질문하고 고민하자. 이 과정은 앞으로 개발자로 커리어를 쌓아 나갈 때 중요한 발판이 될 것이다.

0개의 댓글