페이스북이 2020년 5월에 소개한 React 전용으로 나온 상태 관리 라이브러리다. Recoil을 통해 전역 상태를 관리하면 코드가 굉장히 간결해진다
Redux의 경우 Flux 패턴을 사용하여 안정적으로 상태 관리가 가능하다.
그럼에도 Redux에 대한 불만이 꾸준히 나오는 데에는 이유가 있을 것이다.
- React 전용 라이브러리가 아니다.
- 초기 복잡한 세팅이 요구된다.
- 비동기 데이터를 사용하려면 미드웨어 설치 등 추가적인 라이브러리 설치를 필요로 한다.
Recoil은 이러한 단점을 보완한 라이브러리다.
최상위 컴포넌트를 RecoilRoot로 감싸주면 된다
RecoilRoot가 감싼 하위 컴포넌트들은 이 컨텍스트를 통해 Recoil 상태와 관련된 동작을 할 수 있다.
Recoil 상태가 변경될 때 하위 컴포넌트들에게 리렌더링을 트리거 한다
Recoil 상태가 변경되면 해당 상태에 의존하는 컴포넌트들은 자동으로 업데이트되어 새로운 상태를 반영한다.
import React from "react";
import { RecoilRoot } from "recoil";
import Counter from "./Counter";
funtion App() {
return (
<RecoilRoot>
<Counter />
</RecoilRoot>
);
}
Atoms 는 상태(state)의 일부를 나타낸다. Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다 (전역적인 저장소)
atoms.js 파일을 생성하고 Recoil의 atom function을 사용하여 필요한 데이터를 설정한다
atom은 두 가지를 요구하는데 첫 번째는 key로 unique ID 이고 두 번째는 defalut value 이다.
key : atom을 식별하는데 필요한 고유한 문자열
default : 초기값 설정
// atoms.ts
import { atom } from 'recoil';
export const counterState = atom({
key: 'counterState',
default: 0,
});
atom 은 useRecoilState 훅을 통해 해당 상태의 값을 읽고 업데이트 할 수 있다.
아래 코드를 보면 마치 useState 사용하는 것처럼 counterState의 초기값 0이 count가 되고 increment 버튼을 누를 때마다 count가 1씩 증가되는 것을 볼 수 있다.
import React from "react";
import { useRecoilState } from "recoil";
import { counterState } from "./atoms";
const Counter = () => {
const [count, setCount] = useRecoilState(counterState);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return (
<div>
<p>Count : {count} </p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
export default Counter;
기존에 선언한 atom 을 전 / 후 처리하여 새로운 값을 리턴하거나 기존 atom의 값을 수정하는 역할을 수행한다
그리고 참조한 atom의 값이 최신화되면 자동으로 selector의 값도 최신화하기 때문에 관리하기에도 편하다
key : selector의 고유한 식별자로 사용되어야한다. 다른 'atom'이나 다른 'selector' 와 구별되어야한다.
get : get 매개변수를 통해 다른 atom 이나 selector의 값을 읽을 수 있다.
get 함수는 get(state) 형태로 호출되며 state는 읽고자 하는 selector 나 atom을 나타낸다 get 함수는 해당 상태의 최신값을 반환한다
아래 코드를 보면 counterState의 최신값을 가져오는 역할을 한다. counterState는 atom 으로 정의된 상태이며, 해당 상태의 값을 읽기 위해 get 함수를 사용한다.
// selector.ts
import { selector } from "recoil";
import { counterState } from "./atoms";
// Selector 정의
export const doubledState = selector({
key : "doubledState",
get : ({ get }) => {
const count = get(counterState);
return count * 2;
},
})
selector을 사용하는 컴포넌트에서는 useRecoilValue 훅을 사용하여 selector 값을 읽을 수 있다.
아래 코드에서 doubledState의 get 함수는 counterState의 값을 가져와서 두 배로 계산한 값을 반환한다. 이는 doubledState가 counterState에 의존하고 있음을 의미한다.
즉, counterState가 변경될 때마다 doubledState도 자동으로 업데이트된다.
import React from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { counterState } from "./atoms";
import { doubledState } from "./selector";
const Counter = () => {
const [count, setCount] = useRecoilState(counterState);
const doubledCount = useRecoilValue(doubledState);
const increment = () => {
setCount(count + 1);
}
const decrement = () => {
setCount(count - 1);
}
return (
<div>
<p>Count : {count} </p>
<p>Doubled Count : {doubledCount} </p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export default Counter;