React 상태관리 라이브러리 Recoil을 학습한 내용 정리하는 문서
특징
- Recoil은 context API를 기반으로 구현되었으며, 함수형 컴포넌트에서만 사용할 수 있다.
왜 리코일을 쓰는가?
다른 상태 관리 라이브러리의 한계
- 사실 큰 문제는 없다. 다만 redux, Mobx 등은 React 전용 라이브러리가 아니다. 따라서 React 내부 스케줄러에 접근할 수 없다.
- 지금까지는 큰 문제 없었으나 동시성 모드를 지원하지 않는 문제점이 드러나고 있다.
- 또한 redux의 경우 기본 store 구성을 위한 보일러 플레이트가 너무 복잡하다.
- 비동기 데이터 처리/계산된 값 캐시 등은 다른 라이브러리를 사용해야한다.
이처럼 복잡하고, React와 호환성 관련 이슈가 있기 때문에 가능하면 React 자체 내장 상태 관리 기능을 사용하는게 좋다.
React 자체 상태 관리 기능의 한계
- 공통 상위 요소에서 상태를 관리하고 하위 컴포넌트로 내려주는 방식은 prop drilling 이슈를 야기한다.
- prop drilling 이슈는 context API로 해결 가능하지만, context는 단일 값만 저장할 수 있다. 자체 consumer가 존재하는 값을을 묶을 수 없다.
이 두 가지 특성은 트리의 최상단 - 하위 요소까지의 코드 분할을 어렵게 한다.
또한 라이브러리를 사용하지 않는다는 것은, 상태 관리와 관련된 동작을 모두 직접 구성해야한다는 것이다. 특히 서버 캐싱 관련 작업은 매우 까다롭다.
- 주기적인 폴링
- 포커스시 재검증
- 네트워크 회복시 재검증
- 지역적 상태 변경
- Error Retry
- 페이지네이션/스크롤 위치 복구
이와 같은 동작을 모두 직접 구현해야한다..
Recoil은 가능한 React다움을 유지하면서 이러한 문제를 개선하고자 등장했다
Recoil의 주요 개념
Recoil은 atoms(공유 상태) => selectors(순수 함수) => React Component로 흘러가는 data-flow graph 구조이다.
RecoilRoot
- Recoil은 내부적으로 context API를 사용하기 때문에, 마찬가지로 Provider가 필요하다.
- 보통 최상단(App)에 둔다.
- 중첩이 가능하며, 중첩 된 경우 Recoil API는 가장 가까운 조상 RecoilRoot에 접근한다.
Atom
- Recoil의 단위 데이터. 컴포넌트가 구독할 수 있는 상태의 단위.
- atom이 업데이트되면 해당 atom을 구독하고 있는 컴포넌트가 업데이트된 값을 기반으로 리렌더링 된다.
const userState = atom({
key : 'user',
default : {
firstName: 'Gildong',
lastName: 'Hong',
age: 30
}
})
key
- atom의 global하고 고유한 값.
- 디버깅, 지속성, 고급 API(모든 atoms의 map을 볼 수 있는 기능 등)에 사용된다.
default
Selector
- atoms 상태값을 동기/비동기 방식을 통해 변환하는순수 함수
- 가공된 데이터를 받거나(get), 데이터를 가공하여 store에 저장(set)하고 싶을 때 사용한다.
const userNameSelector = selector({
key : 'userName',
get : ({ get }) => {
const user = get(userState);
return `${user.firstName} ${user.lastName}`
},
set : ({ set }, name) => {
const names = name.split(' ');
set(
userState,
(prevState) => ({
...prevState,
firstName : names[0],
lastName : names[1] || ''
})
)
}
})
key
atom과 마찬가지로 고유한 값이다.
get
- 데이터를 가공하는 함수다. 첫 번째 인자로 받는 객체 안의 get을 통해 atoms이나 다른 selector에 접근할 수 있으며 이 때 자동으로 종속 관계가 생성된다.
- 따라서 접근한 atom/selector가 업데이트 되면 이 함수도 다시 실행된다.
set
- 이 속성은 필수는 아니지만, 작성한다면 해당 seletor는 writable(쓰기 가능한) RecoilState 객체를 반환한다.
- 첫 번째 인자로 객체(get, set, reset을 포함), 두 번째 인자로 새로운 값을 받는다.
- 첫 번째 인자 객체 안에 있는 set으로 다른 atom값을 set할 수 있다.
dangerouslyAllowMutability
selector는 순수 함수이기 때문에 동일 입력 동일 반환이어야 한다. 이를 위해 selector에 저장된 모든 값을 기본적으로 고정시키는데, 경우에 따라 이 옵션을 통해 재정의해야 할 수 있다.
참고 아티클