(위 링크의 글을 보시면, 흐름 이해가 쉽습니다)
하나의 atom 상태를 가지고 컴포넌트마다의 커스텀 훅을 불러오려니, 중복적인 서버 통신이 일어난다.
Recoil 로써 캐싱을 할 방법은 없을지 알아보자.
각 reviewId 에 맞는 책 정보 데이터를 비동기로 불러와 관리하고,
각 컴포넌트에서의 중복적인 데이터 패칭을 막기 위해 selectorFamily를 이용하였다.
이 때 selector는 캐싱 기능을 제공하며, 한번의 api call으로 처리할 수 있도록 도와준다.
Recoil은 📎 selector로 비동기 패칭을 지원한다.
구현 방법은 간단하니, 문서를 참고하면 좋을 것 같다.
Recoil 를 이용하여 비동기로 데이터를 패칭하는 여러 방법이 있다.
“fetch only one at the time, using a selectorFamily”
앞 포스팅에서 보였던 꼬리 질문/답변 기능은 “비동기로 패칭한 데이터를 기반한 전역 state”가 필요했다.
selectorFamily로 비동기 패칭을 구현하고, 이를 기반한 전역 state는 atom 으로써 동작하게끔 한다.
Selector 로 비동기 패칭이 완료된 데이터는 Atom 에 업데이트 한다.
이와 같은 구조로 설계함으로써 아래와 같이 수많은 중복 통신을 방지할 수 있었다.
->
⛔️
Recoil 은 Facebook에서 만들어진 라이브러리로, Suspense와의 호환성이 좋다.
하지만 작업을 하다보니
Next app 을 build 할 때, static page 를 생성할 때에 계속해서 timeout이 발생해 build가 되지 않는 이슈가 발생하기도 한다 (static-page-generation-timeout)
찾아보니, Next 에서 Recoil의 selector 와 Suspense 를 함께 사용할 수 없는 📎 이슈가 있었다.
◽
◽
◽
왜 그럴까?
◽
RQ, SWR과 같은 패칭 라이브러리는 fetch-on-render 의 방식으로,
컴포넌트 렌더링 이후에 네트워크 요청을 한다.
◽
React18의 Suspense 기능은 render as you fetch 을 지원하는데,
네트워크 요청을 하고 컴포넌트 렌더링을 이뤄지도록 한다. 이 때, 데이터가 다 불러와짐(stale data)을 가정하고 fallback으로 넘겨준다.
에러 대신 Promise를 throw 하는 것을 Suspense가 감지할 수 있게 된다.
◽
이를 이용해 Recoil async selector는 Promise를 throw 하여 Suspense를 지원하도록 하지만,
Next app의 SSR에서는 데이터 패칭이 끝나지 않아 timeout 이 일어나는 게 아닐까 하는 📎 의견이 있다.
◽
◽
◽
이를 해결하기 위해 Recoil은 fetch-on-render 방식의 Loadable을 지원한다.
(아쉽지만 로딩처리에 대한 로직 구현을 Suspense 로의 추상화는 다음 과제로 남겨놓고,)
📎 useRecoilValueLoadable 훅으로 세가지 상태에 대한 예외 처리를 해주자. (이 역시 공식문서의 예제가 잘 나와있기에, 설명을 대신 해주리라 생각해요)
useRecoilValueLoadable 훅은 Suspense를 위해 비동기로 값을 읽어올 때 Error 혹은 Promise를 던지지 않고, “Loadable” 객체를 리턴한다.
hasValue, loading, hasError 3가지 상태의 Loadable 객체로써 컴포넌트를 분기 처리하여 나타낸다.
하여,
Recoil 을 활용해 atomic 한 전역적인 상태를 관리할 수 있었고,
해당 페이지에 대해 중복되는 서버통신을 캐싱하여 막아주었다
◽
설계 양, 사용법이 다소 간단한 Recoil 을 사용하여 작업 시간이 그렇게 길지는 않았지만, 사용할 수록 아쉬운 부분들도 많았다
특히, 서버 사이드 데이터 관련한 기능이 react-query, swr에 비교도 안 될만큼 부족하고,
데이터 갱신과 같이 불안정한 기능들이 많다.. 📎 수많은 ISSUE들이 대기 중이다
그러나 간단하게 전역으로 상태를 관리하고, 로직을 효율적으로 설계하여 관리하기에는 굉장히 편리하였기에, 서비스에 맞게끔 맞는 기술을 사용하면 좋겠다.
◽
북스테어즈는 이 작업을 시발점으로 다시금 작업을 시작하게 되었다.
개발을 처음 접하던 우리는 기본기에 충실하며 라이브러리를 최소화하는 개발을 하였다.
심지어 객체의 깊은 복사, Debounce, Unmount Animation 모두 직접 구현하였다.
그리고 지금, 로딩 및 에러처리나, 반응형 작업이나, 부분부분의 리팩토링, … 뜯어낼 구석이 많지만 :( …~
오히려 이 과정이 개념을 더 깊게 와닿게 해주었고 더 멀리 나아갈 수 있다는 자신감을 주었다.
이 모두가 팀원들에게 성장의 발판이 되기를 바란다.
작성자 :: IN SOPT 웹파트장 이주함