Recoil은 React를 위한 상태 관리 라이브러리이다.
Recoil은 Facebook에서 만들어졌다. React를 위해 만들어진 상태 관리 라이브러리이기 때문에 React처럼 작동을 하며 기존의 React를 사용하였던 개발자라면 쉽게 접근할 수 있다.
// useState
const [id, setId] = useState(0);
// recoil
const [count, setCount] = useRecoilState(countState);
stor, action, reducer등 여러가지를 신경 쓸 일 없이 초기 세팅이 직관적이고 간단하다.
또한, 비동기 데이터 흐름을 위한 내장 솔루션까지 제공된다. 앱 전체의 모든 상태 변경을 관찰하여 지속성, 라우팅, 디버깅을 구현하는데 용이하다.
npm install recoil
yarn add recoil
recoil을 사용하기 위해서는 사용하고자하는 부모컴포넌트에다 RecoilRoot
를 사용한다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { RecoilRoot } from 'recoil';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<RecoilRoot>
<App />
</RecoilRoot>
);
Atoms는 Recoil의 상태를 표현하는, Recoil에서의 상태 단위이다.(redux의 store와 같은 개념)
Atoms이 업데이트되면 해당 Atom을 구독하고 있던 모든 컴포넌트가 업데이트된 Atom값을 참조하여 리렌더링 된다.
Atoms은 다음과 같이 Key,Value 값을 가지고 있으며 (es6의 Map을 사용한다고 함) 각 Atom은 자신의 고유한 Key 값으로 구분된다.
따라서 Atoms은 App 전체에서 다른 Atom과 Selector와 구분되는 자신만의 Key값을 가져야한다.
import { atom } from "recoil";
const textState = atom({
key: 'countState',
default: 0,
});
atom은 key와 default값을 설정해주어야한다.
atom을 식별하는데 필요한 고유한 문자열이다.
프로젝트 전체에서 다른 atom,selector에 대해 고유해야한다.
초기값을 설정해준다.
atom에서는 불가능한 비동기 처리와 복잡한 로직을 구현할 수 있다.
Selector는 파생된 상태(derived state)의 일부를 나타낸다.
파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.
import { DefaultValue, selector } from "recoil";
import countState from "../atom/countState";
export default selector({
key: "countSelector",
get: ({get}): number => {
const count = get(countState);
return count + 1;
},
set: ({set, get}, newCount)=>{
return set(countState, newCount + 10)
}
})
atom의 key와 동일하며 프로젝트 전체에서 고유한 문자열을 가져야 한다.
get은 countState를 get하고 있으면 countState가 바뀔 때마다 새로운 값을 리턴해준다.
get()을 여러번 사용 가능하고 그중 하나라도 변하게 되면 리렌더링이 된다.
get: ({get}): number => {
// countState를 구독하고 있습니다.
// countState가 바뀔 때마다 1증가 시켜서 반환합니다.
const count = get(countState);
return count + 1;
},
set없이 get만 제공되면 selecotor는 read-only한 상태이지만 set을 제공하면 쓰기 가능한 상태를 반환한다.
set은 selector의 값을 수정하는 것이 아닌 수정 가능한 atom의 값을 바꿔준다.
set: ({set, get}, newCount)=>{
// 설명을 위한 코드로,
// 현재 count는 사용하고 있지 않습니다.
const count = get(countState);
return set(countState, newCount + 10)
}
set안에서의 get()은 구독하지 않고 단순히 atom이나 selector의 값을 찾는데 사용한다.
만약, 전달받은 새로운 값이 없데이트 함수나 초기화 액션이라면 DefaulValue 일 수도 있다.
const myQuery = selector({
key: 'MyQuery',
get: async ({get}) => {
return await myAsyncQuery(get(queryParamState));
},
});
atom을 직접 사용할 때 비동기 통신을 하는게 아닌 위 코드와 같이 seletor안에서 비동기 통신 후 값을 사용할 수 있다.