[if(kakao) 2021] '카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유' 리뷰

nhchoi·2021년 11월 18일
4

if(kakao) 2021

목록 보기
2/2
post-thumbnail

해당 포스팅은 매년 진행되는 카카오의 컨퍼런스인 if(kakao) 2021에서
카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유 세션을 듣고 작성한 내용 정리 및 후기입니다.

결론부터 말하자면
카카오페이 웹뷰에서 더 나은 사용자 경험을 제공하기 위해 React Query를 선택했음 !!!!


React-Query란?

리액트 애플리케이션에서 서버의 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트하는 작업을 도와주는 라이브러리

기본적으로 사용하는 React는 서버로부터 데이터를 불러오기 위한 특정한 구현은 존재하지 않음
대신, 리액트 컴포넌트에서 useEffect Hook을 사용해서 API를 호출하거나 Redux와 같은 global state를 통해 API를 호출하여 사용

여기서 더 좋은 사용자 경험을 위해 Cache, Retry, Refetch를 추가한다면, 고려해야할 사항들이 늘어나기 시작한다.
위 사항들을 직접 구현해야한다면? 안그래도 부족한 리소스가 더 소모될 것이다......


React Query를 사용하면 큰 리소스 소모 없이 위 기능들을 추가할 수 있다
(더 리액트스럽게 API 관리를 할 수 있다.)

React Query에서는 useQuery, useMutation Hook을 제공한다.
이 Hook들을 사용하면 API 내부에서 요청 및 관리를 효율적으로 수행할 수 있다.

  • React Query의 Hook을 통해서 API를 호출하고 나면 React Query는 내부적으로 관리하는 QueryClient를 사용하여 API 데이터를 캐싱함
  • 만약 동일한 API 요청을 진행하게 되면 queryClient에 저장되어있는 캐시데이터를 컴포넌트에서 사용할 수 있게끔 반환해주게됨
  • 그 외에도 QueryClient는 LocalStorage를 통한 Persistent Data Caching이나 브라우저의 Focus, Online 이벤트 등을 감지하여 데이터를 갱신하는 일 등의 부가작업을 진행하기도 한다.

useQuery

// 가장 기본적인 형태의 React-Query useQuery Hook 사용 예시
const { isLoading, error, data } = useQuery(	
  queryKey,
  fetchFn,
  options
);
  • isLoading : 요청의 상태 및 정보
  • queryKey : Response Caching을 위해 각 요청을 구분하기 위한 Key
  • fetchFn : Date Fetching을 수행할 Fetch 함수 (eg. Axios, Fetch, Etc...)

React Query를 사용한 Data Fetch

  • QueryClient 인스턴스 생성 후 QueryClientProvider에게 전달하여 기본적인 환경 구성
// React Query의 코어를 담당하는 인스턴스
const queryClient = new QueryClient();
// React Application에서 사용하기 위해
function App() {
	return (
		<QueryClientProvider client={queryClient}>
			<Users />
		</QueryClientProvider>
	);
};
  • 실제 API 요청을 진행하는 컴포넌트에서 useQuery Hook을 사용하여 API 서버로부터 값을 가져오고 사용하게 됨
const { isLoading, error, data } = useQuery(
	'userInfo',
	() => axios.get(URL)
);

API 호출 상태나 결과와 같은 대부분의 값들은 Hook의 리턴값을 통해 접근하게 됨

useQuery Hook parameter

  • 첫번째 parameter로는 해당 요청을 다른 요청들과 구분하기 위해 사용되는 query key를 전달한다. React Query는 이 key 값을 사용하여 내부적으로 데이터를 캐싱하고 관리함.
    • query key로는 String / Array 사용 가능
      • Array를 사용할 경우 Array의 아이템으로는 직렬화 가능한 모든 자바스크립트 객체를 사용할 수 있다.
  • 두번째 parameter로는 실제 API 요청을 수행하는 비동기 함수를 전달한다.

React-Query는 fetch나 axios를 대체하는 라이브러리가 아니다!
API를 통해 불러온 서버의 상태를 내부적으로 캐싱하고 지속적으로 동기화하는 등 사용하기 좋게 도와주는 라이브러리임
따라서, 실제 API 요청을 수행하는 함수는 fetch나 axios를 통해 구현해야함

useMutation

React Query에서는 서버 상태를 수정하기 위해 사용 가능한 useMutation Hook을 제공함
POST, PUT, DELETE에 대응되는 API 요청을 전송하여 서버의 데이터를 변경할 수 있게 지원함

// 가장 기본적인 형태의 React-Query useMutation Hook 사용 예시
const { mutate, isLoading, error, data } = useMutation(
	mutationFn,
	options
);
  • mutate : 수정 요청을 실행하는 함수
  • isLoading : 요청의 상태 및 정보
  • mutationFn : Date Mutation을 수행할 Fetch 함수

React Query를 사용한 Data Mutate

const { mutate, isLoading } = useMutation(
	value => axios.post(URL, {value})
);

useQuery와 마찬가지로 리턴값을 통해 API 로딩 여부, Response Data, Error등을 제공함.
useMutation은 추가적으로 mutate라는 메소드를 리턴값으로 제공함
mutate를 사용하여 원하는 시점에 서버로 API 요청을 보낼 수 있다.




카카오페이 FE는 React-Query를 이렇게 쓴다더라.

React Query with Custom Hook

API 별로 커스텀 훅을 만들어서 사용하면 API를 손쉽게 체계적으로 관리할 수 있다.
API 마다 useQuery를 Custom Hook으로 wrapping함

장점설명
직관적으로 API 사용 가능API 별로 Custom Hook이 나누어져 있어 직관적으로 API를 사용할 수 있음
API 전처리 / 후처리 가능Custom Hook 내부에서 API 전처리,후처리 하여 간결하고 이해하기 쉬운 Component 작성 가능
휴먼 에러 방지Query Key가 Custom Hook 레벨에서 적용되기 때문에 캐싱 등 작업에서 휴먼 에러 방지 가능
API 특성에 맞는 Option 설정 가능API 특성별로 캐싱 등 React Query Option 설정 가능
API 연관 관계 처리 용이여러 API가 연관되는 관계를 갖는 경우 용이하게 처리 가능

추가 설명

  1. 직관적으로 API 사용 가능
    • Custom Hook의 이름을 보고 어떤 데이터를 사용하기 위한 함수인지 직관적으로 알 수 있음
  2. API 전처리 / 후처리
    • 서버 측 요구사항에 맞추어 API 호출에 전처리가 필요한 부분을 custom hook에서 처리함으로서 컴포넌트에서 불필요한 분기처리 없이 간단히 Custom Hook을 사용하여 API를 호출하게 됨(eg. parameter에 따라서 다른 query key를 전달하는 경우)
    • useQueryselect 옵션을 사용하면 API에서 받은 response 데이터를 변경할 수 있다. 변경된 값은 실제로 사용하는 useQuery Hook의 데이터 리턴값이 됨. API 응답 중 후처리가 필요한 부분을 처리함으로서 데이터를 사용하는 컴포넌트에서 불필요한 추가 작업 없이 편리하게 개발할 수 있음
  3. 휴먼 에러 방지
    • 캐싱에 사용되는 query key가 고정되어있기때문에 캐시를 처리할 때 query key를 잘못 입력하는 에러도 방지됨
  4. API 특성에 맞는 Option 설정 가능
    • cacheTime : 데이터의 캐시가 유지될 시간을 지정함
    • refetchOnWindowFocus : 브라우저의 focus에 따라 최신 데이터 확인 여부를 정의함
    • enabled : false인 경우 useQuery는 fetch를 실행하지 않고 기다렸다가 true로 변경되면 fetch를 실행함
  5. API 연관 관계 처리 용이
    • 내부적으로 다른 custom hook을 호출하여 데이터를 받아 useQuery의 parameter로 사용할 수 있음

Persist Data Caching

persistQueryClient

local storage등 자바스크립트에서 접근할 수 있는 data store에 캐시 정보를 저장하여 사용자의 페이지 이탈, 브라우저 종료 후 재접속시에 기존에 캐싱해놓은 정보를 사용하여 빠르게 초기화면을 보여줄 수 있음

persistQueryClient는 아직 실험적인 기능이므로 사용시 유의할 것!




카카오페이 FE는 React-Query를 써보니 이런 점이 좋았다더라.

리덕스는 그만, React Query를 사용하여 API State 관리

API State 관리에 사용되던 Redux 코드를 제거하고, 모든 API State를 React Query를 통해 관리함

  • 프로젝트의 복잡도 감소 : Redux 사용을 위한 수 많은 Boilerplate Code를 제거하므로서 프로젝트의 복잡도를 감소시킬 수 있음
  • 불필요한 로직 제거 : 데이터 캐싱, 로딩 상태 확인 등 React Query에 포함되어 있는 기능을 사용하여서 비즈니스 로직에 집중할 수 있게 됨

React Query 사용하여 사용자 경험 향상

  • Stale-while-revalidate 캐시 전략과 Local Persist Cache를 사용하여 사용자에게 빠르게 첫 화면을 제공
  • RefetchOnWindowFocus 옵션을 사용하여 App 상태에 따른 데이터 최신화 → 사용자가 화면 이탈 후 재접속하는 상황에서 자동으로 API 요청을 진행하여 항상 최신의 데이터로 갱신시켜줌
  • React Query를 사용한 컴포넌트의 Unmount시 Hook이 unmount와 동시에 API 요청을 진행하는 Promise를 Cancel하여 예상치 못한 side effect를 최소화 할 수 있음
    • API 요청들은 리액트 컴포넌트의 생명주기와 관계없이 진행되므로 때때로 컴포넌트가 unmount 되었지만 API 요청 promise는 계속 진행되는 케이스가 있음
    • 만약 axios의 interceptor 기능을 사용하는 경우에는 개발자의 의도와 다르게 side effect가 발생할 가능성도 있음


결론

React Query는 React Application에서 서버의 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트하는 작업을 도와주는 라이브러리이다.

복잡하고 장황한 코드가 필요한 다른 데이터 불러오기 방식과 달리 React Component 내부에서 간단하고 직관적으로 API를 사용할 수 있다.

더 나아가 React Query에서 제공하는 캐싱, Window Focus Refetching 등 다양한 기능을 활용하여 API 요청과 관련된 번잡한 작업 없이 "핵심 로직"에 집중할 수 있다.









카카오가 얼마나 사용자 경험에 포커스를 두고 서비스를 제공하는지 알 수 있었던 세션이었습니다.
잘 들었습니다 :)





profile
👩‍💻

0개의 댓글