[React] React Query

Sanghyeok·2022년 7월 27일
5

React

목록 보기
2/2
post-thumbnail

22.07.27


서론이 깁니다! 시간이 없으시다면(또는 남의 면접 썰에 관심이 없으시다면) 이 글의 출처인 react-query에 대해서 너무 잘 설명해놓은 글 (<< 클릭)을 읽어주세요!


들어가며

취업 준비 기간동안 여러 기업에서 기술 면접을 봤었는데, 그 중 인상 깊었던 면접이 있었습니다.
면접을 본 지 조금은 오래 되어서, 질문과 답변의 내용이 정확하지 않을 수 있지만 대략적으로 다음과 같은 흐름으로 진행되었습니다.

Q. React의 장점( ? 특징 ? )이 무엇이라고 생각하시나요?

  • React는 가상 DOM을 기반으로, 변경이 일어난(상태 또는 props의 변경 등) 부분에서만 DOM을 업데이트함으로써 뛰어난 성능을 자랑합니다.

Q. 그렇다면 React에서 상태관리 라이브러리를 사용해보셨나요?

  • Redux와 간단하게나마 Recoil을 사용해보았습니다.

Q. 상태관리 라이브러리를 사용하는 이유는 무엇이라고 생각하시나요?

  • React로 개발을 하다보면 상위 컴포넌트에서 사용하는 상태를 하위 컴포넌트로 전달해야 하는 일이 생깁니다. (하나의 상태를 복수의 컴포넌트에서 참조하거나)
    문제는 규모가 어느정도 커지면 (depth가 깊어지면)
    props의 전송이 반복이 되고 (props-drilling) 이는 유지보수와 오류 추적에 좋지 않다고 생각합니다.
    하여, 이러한 state들을 전역에서 관리하기 위해 상태관리 라이브러리를 사용한다고 생각합니다.

Q. Redux와 Recoil에 대해서 설명해주세요

  • Redux는 flux 패턴(단방향 데이터 흐름) 기반으로, 사용자의 action이나 데이터의 변경 등을 쉽게 관찰할 수 있고
    점유율이 가장 높은 라이브러리 답게 자료가 가장 많습니다. 하지만 러닝커브가 높고 보일러 플레이트 코드의 양이 많다는 단점이 있으며
    thunk, saga같이 비동기 처리 라이브러리에 의존한다는 단점이 있습니다.

  • Recoil은 Atomic 모델을 기반으로 atom이라는 단위로 상태를 관리합니다. 러닝커브가 낮고, 보일러 플레이트가 없다 싶은 수준입니다. 또한 React를 만든 Facebook(현 Meta 맞나?)에서 Context API 기반으로 개발을 해서 React에 더욱 어울리고, 상태 변경에 따른 불필요한 렌더링이 발생하지 않습니다. 또한 비동기 처리 기반으로 작성되어 Redux와 같이 다른 라이브러리에 의존하지 않아도 된다는 장점이 있습니다. 하지만 Redux에 비해 자료가 적고 직관적이지 못하다는 단점이 있습니다.

Q. Atomic 얘기가 나와서 말인데, Atomic하게 개발을 했다는 전제 하에 각 컴포넌트들은 오직 자신이 사용하는 state만 바라보면 된다.
만약 그렇지 않다면 (컴포넌트가 다른 컴포넌트의 state를 참조해야 한다면) (= 상태관리 라이브러리를 이용해 전역으로 어떤 상태를 관리한다면)
Atomic하게 개발을 했다는 전제 자체가 부정이 되는 건데 이에 대해서 어떻게 생각하시는지?

띠용?

이 질문에 대해서는 평소에 생각해본 적도 없고, 그저 깊이 있는 생각 없이 단순히 어떤 기능을 구현하기 위해 (또는 내가 편리하기 위해)
상태관리 라이브러리를 사용한 것인가 라는 생각이 들어서 대답을 제대로 하지 못했던 기억이 있습니다.

굉장히 감사하게도 이 부분에 대해 피드백을 해주셨습니다. 자세하고 길게 설명해주셨는데 간략하게 요약하면 다음의 내용과 같은 느낌이었습니다.

전역에서 다뤄지는 데이터는 Server에서 전달해주는 것으로 충분하고 React에서 상태관리는 UI적인 요소들을 다루는 것에 사용을 한다.

솔직하게, 면접이 끝났을 당시에도 이 질문(+피드백)이 너무 충격적이었고
머리로는 이해했지만 가슴으로는 받아들이지 못했습니다.(틀렸다고 생각해서가 아니라 정말 개발의 깊이가 부족하다는 생각)
지금도 너무나도 많이 부족한 주니어 개발자이지만, 그 당시는 지금보다도 더더욱 부족했던 사람이었으니까요 하핫

그렇다면 그놈의 상태(State)가 도대체 뭘까요


React에서의 State

React에서 일반적으로 사용하는 상태(state)를 세가지로 구분부터 하고 시작합시다!

  • Local State : React Component안에서만 사용되는 State
  • Global State : Global Store에 정의되어 프로젝트 어디에서나 접근할 수 있는 State
  • Server State : 서버로부터 받아오는 State

기존 Redux와 같은 상태 관리 라이브러리는 Global State와 Server State를 전부 포함하는 방법으로 개발을 했었다고 합니다.
Redux에서 Server State를 처리하기 위해, 위에서 언급한 Redux의 비동기 처리 라이브러리인 sagathunkmiddle ware로 사용해야 합니다.
문제는 어떤 시점에서 state 변경이 반영되는지 정확하지 않고, 실시간으로 변경되는 data를 다룰 때,
data가 언제 stale(유통기한이 지남) 해지는지에 대해 다루기가 까다롭다고 합니다.


아주 대표적인 예시가 있죠!
유튜브 동영상, 페이스북 댓글, 인스타그램 게시물의 좋아요는 아주 실시간으로 변경됩니다.
그렇다면 이 좋아요 수를 최대한 실시간으로 반영하기 위해선 적절한 타이밍에 API가 re-fetch 되어야하겠죠?
Redux는 이러한 타이밍마다 API 콜을 (당연하게도) 반복 호출 하고 state를 관리하는 store도 비대해지고 아주 그냥 난리도 아닌 그렇습니다.


React Query

제목인 React Query에 대해서 이제야 언급하게 되다니.. 이래서 설명충은 안되나 봅니다.
SWR과 함께 대표적인 서버 상태 관리 라이브러리, data fetching 라이브러리인 React Query는 앞서 말한 Redux의 단점을 해결해줍니다.
우선 코드를 볼까요 !
판매량을 조회하는 기능을 만들고 싶다고 칩시다!

import { useQuery } from 'react-query';

export const Sale = () =>{
  const { isLoading, data } = useGetSales(
    'sale',
    isSearch
  );
  
  return (
    <div>
    { isLoading 
     ? <h1> Loading... </h1>
     : <div> {data.map((value,idx) => <li key={idx}> {value.sold} </li>} </div>
    </div>
  )
}
import { saleAPI } from '../../../apis/sale/sale';

export const useGetSales = (queryKey: string, isSearch: boolean) => {
  return useQuery(
    queryKey,
    async () => {
      return await saleAPI
        .getSale('2022-06-22', '2022-07-22')
        .then((res) => {
          // console.log(res);
          return res.data.data;
        })
        .catch((err) => {
          console.error(err);
        });
    },
    {
      enabled: isSearch, // isSearch가 true일때만 query가 실행됩니다.
    }
  );
};

useQuery에 첫 번째로 전달되는 인자 queryKey(필수) 는 unique한 key값으로 unique하기만 하다면 (string, array)에 한해 무엇이든지 될 수 있습니다.
두 번째로 전달되는 인자는 콜백함수(필수, queryFn이라고도 설명하는 외국 글들이 많더라구요!)로 promise를 return하는,
우리가 fetch, axios를 이용해 서버로부터 데이터를 전달받는 함수를 전해줍니다.
세 번째로 전달되는 인자는 옵션으로 enabled, retry, staleTime 등을 설정해줄 수 있습니다. 이름이 옵션인 만큼 필수는 아니겠죠?

then에서 결과로 res.data.data (res를 이용한 뭐든)를 return해주는데, 이게 {data} 로 들어가는 값입니다
{isLoading} 역시도 return을 받게 되면 true에서 false로 자동으로 변경이 되어 로딩 중입니다 등의 처리를 손쉽게 사용 가능합니다!

사용 방법을 다루는 글들은 좋은 글들이 이미 너무 많아서 자세하게 다루지는 않겠습니다!

면접과의 연결 ..?

React Query를 학습하고 난 후 앞에서 언급했던 면접의 피드백이 딱! 떠올랐습니다.
제가 면접에서 했던 대답은 Global State와 Server State를 같이 다루는 Redux 방식으로 대답을 했었던 것이고
피드백은 Server State를 따로 구분해 다루는 Data Fetching 라이브러리에 대한 설명이었다는 걸 깨닫게 되었습니다.

'아 .. 그래서 React Query + Recoil이 요새 떠오르는 조합이구나
Global State(주로 UI 처리를 위한)는 러닝커브도 낮고, 코드량도 적은 Recoil로 충분하고
Server State는 data가 stale하지 않고 실시간으로 반영되게 하기 위해 React Query, SWR을 이용하면 될 것 같은데?'라는 생각이 들었습니다.

사실 정확하지 않을 수 있고 틀린 생각일 수 있지만(얼마든지 반박, 피드백 환영입니다!) 이 흐름을 한 번 정리하기 위해 이렇게 글을 쓰게 되었습니다.

앞으로도 꾸준한 공부를 통해 수정이 필요한 부분에 있는지, 혹시 틀린 방법론은 아닌지도 계속 고민해보려고 합니다!

마치며

혹여나 면접관님이 피드백해주신 부분이 틀렸더라도(또는 주된 개발 방법론이 아니더라도) 탓하거나 비난의 화살이 돌아가지 않았으면 합니다!
제가 잘못 기억하고 있는 부분일 수도 있고(농후하고)
지금보다도 깊이가 더 얕은 상태였기에, 같은 내용을 들었어도 잘못 기억하거나 이해했을 저임을 알기에..
또한 상단에 출처로 남긴 링크도 꼭 읽어보시기 바랍니다!

감사합니다!

0개의 댓글