이 글은 Deview: Recoil 왕위를 계승하는 중입니다. 이 영상을 기반으로 정리된 글입니다.
페이스북에서 개발 한 React 전용 상태관리 라이브러리
const countState = atom({
key: 'count',
default: 0,
})
아톰에서 파생된 데이터 조각.
하나의 selector는 두가지 역할을 다 할 수 있기도 하고, 순수 함수 역할만 해도된다.
slector는 {key, get}
구조로 선언한다. 값을 선언하는 역할을 한다면 setter도 넘겨주면 된다.
const oddEvenState = selector({
key: 'oddEvenState',
get: ({get}) => {
const count = get(countState);
return count %2 ? '홀' : '짝';
}
})
atom과 다르게 selector에는 default가 없다. atom의 파생데이터이기 때문이다.
selector getter의 인자에는 상태값을 결정하는 객체가 전달 된다. setter의 인자로는 ({get, set, reset})을 받는다.
<RecoilRoot/>
Recoil Hook은 atom, selector가 공통으로 사용할 수 있다.
useRecoilValue
읽기 전용 Recoil Hook. setter없이 상태값만 반환한다.
const oddEven = useRecoilValue(oddEvenState);
useRecoilState
값을 구독하여 변경할 수 있다. useState
와 동일한 형태로 [상태, setter]를 반환한다.
const [count, setCount] = useRecoilState(countState);
useSetRecoilState
setter함수만 반환한다.
useResetRecoilState
상태를 기본 값으로 초기화 한다.
useRecoilValueLoadable
비동기 전용 hook.
useRecoilValue
랑 유사하게 사용되며 Loadable 객체를 반환한다.
Loadable 객체 안에는 selector getter에서 반환한 상태(.contents)와 비동기 동작의 상태를 포함하고 있다.
Loadable = {
.state, // 상태 ('hasValue' || 'loading' || 'hasError')
.contents, // 실제 콘텐츠 (사진 url..)
}
useRecoilStateLoadable
비동기 전용 hook.
useRecoilState
와 유사하게 사용되며 Loadable, setter 함수를 반환한다.
스피커: 다른 상태 라이브러리보다 비동기를 다루기 수월!
비동기코드를 동기식코드와 거의 유사하게 다룰 수 있고 비동기를 처리하는데 별도의 third-party 라이브러리가 필요 없다.
export const randomImage = selector({
key: 'randomImage',
get: async () => {
const response = await fetch('/api/url');
const data = await response.json();
return data.file;
}
});
< React.Suspense>
로 비동기 데이터를 받는 컴포넌트를 감싸 비동기 작업을 수행할 수 있다.
export default function App() {
return (
<div className="App">
<h1>Random Image</h1>
<RecoilRoot>
<React.Suspense fallback={null}>
<RandomImage />
</React.Suspense>
</RecoilRoot>
</div>
);
}
React Suspense
컴포넌트를 완전히 렌더링할 수 있게까지 렌더링을 멈추는 컴포넌트.
현재 실험단계로 비동기로 데이터를 받아오는 컴포넌트를 감싸준다.
fallback prop에는 기다리는 동안 보여줄 컴포넌트를 전달한다.
Recoil에서 비동기 데이터는 Loadable이라는 객체로 변환할 수 있다.
Loadable를 사용하려면 useRecoilValue를 비동기 전용 hook으로 바꿔줘야 한다.
Suspense를 처리할 때는 error 바운더리를 사용하거나 selector에서 try catch를 통해 에러 트래킹 필요하지만,
Recoil 비동기 hook 자체 예외를 발생시키지 않는다.
Loadable.state === loading → .contents는 Promise
Loadable.state === hasError → .contents는 Error
function UserInfo({userID}) {
const userNameLoadable = useRecoilValueLoadable(userNameQuery(userID));
switch (userNameLoadable.state) {
case 'hasValue':
return <div>{userNameLoadable.contents}</div>;
case 'loading':
return <div>Loading...</div>;
case 'hasError':
throw userNameLoadable.contents;
}
}
selector안에서 사용되는 atom에는 자동으로 의존성이 걸린다.
의존성이 걸린 값(atom) 변결 될 때 마다 파생된 selector가 변경된다.
의존성 걸린 값이 같으면 내부적으로 반환값을 메모이즈 하고 있어 캐싱된 값을 반환한다.
export const animeList = selector({
key: 'animeList',
get: async ({ get }) => {
const keyword = get(keywordState); //keywordState 는 atom
const response = await fetch(
`https://api.jikan.moe/v3/search/anime?q=${keyword}&rated=pg13&page=1`
);
const data = await response.json();
return data.results;
}
});
장 | 단 |
---|---|
React와 연계성이 좋음 | Hooks를 통해서만 사용 가능 |
사용법이 직관적이고 단순 | 프로덕션 레벨에서 사용하기엔 부담 |
비동기 데이터 다루기 수월 | 현재는 디버깅 도구 지원 미미 |
https://ui.toast.com/weekly-pick/ko_20200616
https://medium.com/@songc/recoil-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-14921ad200aa