Randomly 프로젝트 - React-Query 적용기
카테고리 기능 구현 이후로 많은 리팩터링을 했다.
차근차근 정리를 해보려고 한다.
그 중 가장 먼저 React-Query를 적용한 것을 기록하려고 한다.
❓ 도입한 이유
남들이 다 쓴다고 쓰는 것보다 내가 진짜 쓰고 싶다고 느낄때 사용하고 싶었다.
필요할때마다 기술을 도입하였기 때문에 이번 randomly 프로젝트를 하면서 리팩터링을 자주 하게 되었는데, 그럴때마다 각 기술들이 어떤 부분들에서 이점이 있는지를 잘 느끼게 되었다.
예를 들어, RTK를 적용하기 전에 직접 props drilling 으로 값을 내려주면서 컴포넌트를 구성해보고 이후에 적용하여 왜 RTK를 사용하는지를 더 잘 느끼게 되었다.
전역 상태관리를 통해 props drilling을 없애주고 외부 컴포넌트에서도 값을 사용할 수 있어서 너무 편리했다.
그래서 모든 상태 값을 store에서 관리해주었고 각 컴포넌트에서 가져다가 사용하는 식으로 구성했다.
어느정도 기능도 만들어지고, 익숙해진 뒤 내가 적절하게 상태값을 다루고 있는지에 대한 궁금증이 생겼다.
위 코드는 firebase에 저장된 유저의 폴더 정보를 불러오는 로직이다.
페이지가 렌더링 될 때 이 getPackages 함수가 실행되고 firebase에서 데이터를 가져온다.
이후, 이 값을 dispatch를 사용하여 store에 저장한다.
이 저장된 값을 store에 저장하여서 필요한 페이지에서 사용하였다.
하지만, 이 방식은 매 페이지를 렌더링 할 때마다 값을 계속 불러온다는 점이다.
서버에 저장된 데이터를 한 번 불러왔는데, 변경점이 없는 같은 값을 불러오는 것은 불필요한 요청이라 생각되었다.
현재 여기서 불러온 데이터는 MANAGE 페이지말고도 PlayInterview 페이지에서 사용되고 있기 때문에 전역 상태값으로 분류하여 사용하여도 상관은 없다.
하지만, 굳이 전역 상태값으로 분류 하지 않고 첫 렌더링 시에만 데이터를 불러오고 이후에는 값을 캐시해둬서 그 값을 이용하는 것이 더 나을 것 같다고도 생각했다.
꼭 이 방향이 정답이라고는 생각하지 않는다. 하지만, 또 다른 방법으로 구현을 해보고 싶었다.
❓ React-Query 란
React Query는 기본적으로 데이터 가져오기 (data fetching) 및 데이터 관리 (data management) 작업을 처리하는데 초점을 맞추고 있는 라이브러리이다.
이 기술을 사용하면, API 호출, 데이터 캐싱과 같은 작업을 더 쉽게 처리할 수 있다는 장점이 있다.
즉, 서버 측의 데이터와 클라이언트 측의 데이터를 분리해서 사용하는 것이다.
주기적으로 서버 데이터가 변경되는지도 확인하면서 최신 데이터로 유지해주기도 한다.
내가 React-Query를 사용하고 싶은 이유는 바로 캐싱과 재사용성 부분이 가장 크다.
이전에 불러왔던 데이터를 캐싱해서 더 빠르게 불러오고 중복된 요청을 방지할 수 있다.
서버측 데이터와 클라이언트 측 데이터를 분리해서 서버측 데이터를 미리가져오고 클라이언트 측에서 처리한다면, 불필요한 데이터 요청을 줄여 성능면에서 더 이점있다.
또한, API 호출 시 발생하는 오류도 쉽게 처리할 수 있으니 적절하게 사용하면 프로젝트의 질을 더 높일 수 있을 것이라 생각했다.
isLoading 이라는 값으로 데이터가 로드 되었는지를 쉽게 파악할 수 있는 점도 매력적이였다.
🫡 적용해보자!
위에 리팩터링 전 코드에 한 번 적용해보겠다.
먼저 react-query를 사용할 useFolder 라는 파일을 src/hooks 디렉터리 내에 생성해주었다.
기존에 컴포넌트 내부에서 선언하고 호출하였던 API 호출 로직을 따로 hooks 에 분류하여 사용하기로 하였다.
이러면, 재사용성을 높여 다른 페이지에서도 폴더 데이터를 불러올 일 있을때 쉽게 사용할 수 있게 된다.
기존의 데이터를 불러오는 로직과 크게 달라지는 점은 없다.
주목할 부분은 useQuery를 사용하는 부분이다.
useQuery는 데이터를 get 하기 위해 사용하는 api이다.
첫번째 파라미터로는 unique key, 두번째 파라미터로는 api 호출 함수를 넣는다(Promise)
키값은 user마다 달라지게 작성하였다.
folders로 작성하여도 당장은 상관 없을 것 같지만, user마다의 folders 라는 고유의 키값을 만들어주기 위해 사용했다.
이곳에서 설정한 키값으로 다른 컴포넌트에서도 해당 키값을 통해 호출이 가능하다.
만약, user의 이름이 '수현' 이라면 '수현folders' 라는 키 값에 수현 유저의 폴더 데이터 값들이 캐싱된다.
이후 다른 페이지에서 똑같은 요청이 발생하면 getFolder를 또 호출하는 것이 아닌, '수현folders' 키값에 저장된 값을 확인하고 저장된 데이터를 사용한다.
만약, suspense 를 사용한다면 react-query를 통해 글로벌하게 suspense를 적용할 수도 있다.
index.tsx
index.tsx에서 QueryClient에 suspense 옵션을 추가해주고, useQuery 호출시 { suspense: true } 값을 넘긴다.
이후 컴포넌트에 Suspense를 적용해주면 된다. ErrorBoundary도 같이 사용해서 에러 핸들링도 해주면 좋다.
난 두가지 다 하고 있어서 같이 해주었다.
이제 등록한 useQuery의 반환값 isLoading과 isError에 따라 Suspense와 ErrorBoundary가 실행된다.
isLoading 값이 true이면 Suspense, isError 값이 true이면 ErrorBoundary가 실행된다.
다시 데이터부분으로 돌아와서, 이제 이 useFolder를 사용할 페이지에서 호출하여 이 반환 값을 사용하면된다.
return 값으로는 여러 값들이 있는데, 나는 data 값과 isLoading값을 사용한다.
isLoading 값을 통해 데이터 로드가 완료되면 위와 같이 값을 렌더링을 한다.
QA 페이지에서도 useQA 로 react-query 로직을 작성하고 불러오는 기능을 새로 구현해주었다.
리팩터링 전
QA.tsx
리팩터링 후
useQA.tsx
QA.tsx
API 로직을 분리하니 코드가 훨씬 간결해졌다.
좋은 점은 QA 데이터를 사용할 페이지에서 이 로직만 작성하면 손쉽게 캐싱 데이터를 가져올 수 있다는 점이다.
👨💻 후기
적절하게 잘 사용한 건지는 앞으로 더 공부해보고 적용해가면서 더 알아가봐야겠다.
이전에 RTK를 배우고 적용할 때는 전역상태값으로 다루는 것에 초점을 두고 프로젝트를 구성했다면,
이제는 적절한 상태값을 사용하고 있는지에 대해 초점을 맞추고 있다.
모든 값을 전역적으로 다루는 것은 좋지 않다고 느꼈다.
이제는 전역적으로 다루는 데이터들을 다시 분리하고 잘 사용해보려고 한다.
프로젝트를 진행하다보니 성능에도 관심이 많이 생겼다.
최대한 불필요한 렌더링을 줄이고, 적절한 데이터 요청 및 관리, 비동기 로직까지 신경 쓸 부분이 많지만, 하나하나 해결해보면서 프로젝트의 질을 높여나아가고 싶다.
'성장기록 > 프로젝트' 카테고리의 다른 글
Randomly 프로젝트 - React Query로 비동기 처리하기, 상태(state) 다루기 (1) | 2023.03.22 |
---|---|
Randomly 프로젝트 - Storybook 적용기 (0) | 2023.03.19 |
Randomly 프로젝트 - 카테고리별 균등 분배 기능 구현 (0) | 2023.03.11 |
Randomly 프로젝트 - 새 기능 생성 (질문별 카테고리) 에 대하여 (0) | 2023.03.07 |
Randomly 프로젝트 - ErrorBoundary 적용 (0) | 2023.03.06 |