[React] 상태관리 라이브러리 Recoil ♦︎
# React 상태관리
[ 기본 도구 ]
1. useState : 컴포넌트의 로컬 상태를 관리, 단순한 상태 관리
2. useReducer : 상태와 관련된 로직을 함수로 정의하여 구조화 가능, 복잡한 상태 관리
3. useContext : 데이터를 전역적으로 공유할 수 있도록 기본 제공되는 Context API
[ 한계 ]
1. 성능 문제 : Context API 는 상태가 변경될 때마다 관련 컴포넌트가 모두 리렌더링된다.
2. 복잡한 상태 공유시 관리의 어려움
3. 비효율적인 상태 로직
# 상태 관리 라이브러리를 사용하는 이유
1. 효율적인 전역 상태 관리
- 라이브러리는 필요한 컴포넌트만 구독하도록 설계되어 성능을 최적화한다.
ex) Recoil의 Atom, Redux의 connect 등
2. 복잡한 상태와 비동기 작업 관리
- 라이브러리는 전역 상태를 논리적으로 구조화하고, 비동기 작업(API, 캐싱) 을 처리하는 도구를 제공한다.
ex) Recoil의 Selector, Redux의 middleware 등
# 대표적인 상태 관리 라이브러리
1. Redux
2. Recoil
3. mobX
4. Zustand
5. Jotai
6. immer
# Recoil
: Facebook에서 개발한 React 상태 관리 라이브러리
[ 특징 ]
1. 전역 상태와 컴포넌트 로컬 상태를 구분 없이 하나의 방식으로 관리한다.
- 상태를 컴포넌트 트리 전체에서 쉽게 공유하고 사용할 수 있다.
2. Selector을 통한 파생 상태(derived state) 관리
- 상태에서 파생된 값을 선언적으로 정의한다.
3. React의 Suspense와 자연스럽게 통합되어 비동기 데이터를 다루기 쉽게 만든다.
[ 설치 ]
$ npm install recoil
$ yarn add recoil
[ 구성 요소 ]
1. Atom
: 상태(state)의 최소 단위
- Recoil의 상태 저장소로, 기본 값을 가지고 있음
- 어떤 컴포넌트에서나 읽기와 쓰기가 가능한 전역 상태
- atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다.
=> atom에 변화(상태 변경)가 있으면 그 atom을 구독하는 컴포넌트들은 리렌더링된다.
import { atom } from 'recoil';
// 원본 상태 (atom)
const textState = atom({
key: 'textState', // 고유한 ID (필수)
default: '', // 초기값
});
2. Selector
: 파생 상태(Derived State) 를 정의하는 데 사용된다.
- atom 의 값을 가공해서 새로운 값을 만들어주는 함수
- atom이나 다른 selector의 상태를 기반으로 계산된 값을 제공한다.
- 자체적으로 값을 저장하지는 않고, atom의 값이 변하면 자동으로 업데이트 된다.
- Selector은 상태가 변경될 때 필요에 따라 자동으로 재계산되며, 결과를 캐싱한다.
- useRecoilValue(selector)로 가공된 값을 가져올 수 있다 (변경 불가)
- 순수 함수 : 같은 인풋이 들어오면 같은 인풋을 리턴하고, side effect가 존재하지 않는 함수
# 파생 상태
: 기존 상태(state)에서 특정 로직을 적용해 계산된 값을 의미
- 원본 상태를 직접 저장하는 것이 아닌, 기존 상태를 기반으로 계산된 값을 사용하는 방식
[ 기본 구조 ]
const Selector = selector({
key: '키값',
get: ({get}) => {
const 원본 = get(아톰)
return 원본변형값
}
})
사용 예시)
import { selector } from 'recoil';
import { textState } from './atoms';
// 파생 상태 (selector)
const charCountState = selector({
key: 'charCountState', // unique ID
get: ({ get }) => {
const text = get(textState); // Atom의 상태를 읽음
return text.length; // atom 데이터의 길이를 담아두는 selector
},
});
- useRecoilValue() 를 사용해서 charCountState 값을 읽을 수 있다.
function CharacterCount() {
const count = useRecoilValue(charCountState);
return <>Character Count: {count}</>;
}
3. RecoilRoot
: Recoil 상태를 관리하기 위해 애플리케이션 루트에 추가해야 하는 컴포넌트
- 부모 트리에서 RecoilRoot 컴포넌트가 필요하다
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
<CharacterCounter />
</RecoilRoot>
);
}
4. useRecoilState
: Atom의 상태를 읽고 업데이트하는 데 사용하는 Hook
- 컴포넌트가 atom을 불러서 읽고 쓰고 사용한다.
import { useRecoilState } from 'recoil';
import { textState } from './atoms';
function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (e) => {
setText(e.target.value);
};
return <input type="text" value={text} onChange={onChange} />;
}
[ 사용 방법 ]
1. <RecoilRoot>로 컴포넌트 최상단에 감싸주기 (atom이 머무를 곳)
2. atom 생성
3. useRecoilState로 atom 불러오기
- 아니면 useRecoilValue, useSetRecoilState로 분리해서 불러오기
예시)
const [cartItem, setCartItem] = useRecoilState(CartItemAtom)
// 분리해서 둘 중 하나만 가져오는 것도 가능
const cartItem = useRecoilValue() // value만 사용하는 경우
const setCartItem = useSetRecoilState() // set 함수만 사용하는 경우
// atom 초기값인 빈 배열에 아이템 추가
setCartItem((prev)=>[...prev,data])
4. atom 수정 or 사용하기
출처: Recoil 공식문서 https://recoiljs.org/ko/docs/introduction/getting-started
Recoil 시작하기 | Recoil
React 애플리케이션 생성하기
recoiljs.org