Recoil은 React 애플리케이션에서 상태를 관리하기 위한 라이브러리입니다. Recoil에서 제공하는 여러 기능들은 아래와 같습니다.
RecoilRoot
: Recoil의 상태를 전역으로 관리하기 위한 컴포넌트입니다. Recoil을 사용하기 위해서는 애플리케이션의 최상위 컴포넌트에서 RecoilRoot
를 렌더링해야 합니다.atom
: 상태를 정의하기 위한 함수입니다. atom
함수는 상태의 키(key)와 기본값(default)을 인자로 받습니다. atom
함수로 생성된 객체를 사용하여 상태를 읽고 쓸 수 있습니다.selector
: 상태를 파생(derived)하기 위한 함수입니다. selector
함수는 상태의 키(key)와 get
함수를 인자로 받습니다. get
함수는 다른 상태를 읽어와서 파생된 상태를 계산하여 반환합니다. selector
함수로 생성된 객체를 사용하여 파생된 상태를 읽을 수 있습니다.atom
만을 이용해서는 비동기 처리를 하기 힘들기 때문에, 이 과정을 처리하는 용도로도 사용한다.useRecoilState
: 상태를 읽고 쓰기 위한 hook입니다. useRecoilState
함수는 atom
함수로 생성된 객체를 인자로 받습니다. useRecoilState
함수는 배열을 반환하며, 첫 번째 원소는 상태 값, 두 번째 원소는 상태 값을 변경하는 함수입니다.useRecoilValue
: 상태를 읽기 위한 hook입니다. useRecoilValue
함수는 atom
함수 또는 selector
함수로 생성된 객체를 인자로 받습니다. useRecoilValue
함수는 상태 값을 반환합니다.위 기능들을 사용하여 Recoil을 사용하는 애플리케이션에서 상태를 관리할 수 있습니다. atom
함수로 상태를 정의하고, selector
함수로 파생된 상태를 계산할 수 있습니다. useRecoilState
와 useRecoilValue
hook을 사용하여 상태 값을 읽고 쓸 수 있습니다. RecoilRoot
컴포넌트로 Recoil의 상태를 전역으로 관리할 수 있습니다.
한 컴포넌트 안에서의 변수를 상태관리하는 것이 아니라, 앱 전체에서 진행되는 전역 변수를 상태관리 하기 위함이다.
Recoil은 Atom으로부터 시작해서 Selector를 거쳐 React 컴포넌트까지 전달되는 Data-Flow Graph를 생성한다.
selector에서는 Pure 함수가 정의되어야한다. A로 input이 들어왔으면, A가 나와야 한다.
useRecoilState에 의해 정의된 값 / selector를 통해 return된 값을 가져올 때 사용한다.
import {atom, selector, useRecoilValue} from 'recoil';
const namesState = atom({
key: 'namesState',
default: ['', 'Ella', 'Chris', '', 'Paul'],
});
const filteredNamesState = selector({
key: 'filteredNamesState',
get: ({get}) => get(namesState).filter((str) => str !== ''),
});
function NameDisplay() {
const names = useRecoilValue(namesState);
const filteredNames = useRecoilValue(filteredNamesState);
return (
<>
Original names: {names.join(',')}
<br />
Filtered names: {filteredNames.join(',')}
</>
);
}
Recoil atom 혹은 selector의 최신 상태를 대표한다.
리코일 상태에 따라서 렌더링이 가능하다.
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;
}
}