이쪽 컴포넌트에 있는 state를 저쪽 컴포넌트에서 업데이트해야할때.. 다들 고통받은 경험이 있을 것이다. 그래서 전역상태관리 라이브러리를 사용하곤 하는데, 이번에 좋은 기회로 Recoil을 써보게 되었다.
React에 의한, React를 위한! 전역상태관리 라이브러리
Redux나 Mobx같은 것도 있지만 Recoil은 오로지 리액트만을 위해 페이스북에서 2020년 내놓은 상태관리 라이브러리다. 버전이 1도 안되는 따끈따끈한 아이 🔥
npm install recoil
yarn을 쓴다면
yarn add recoil
recoil로 상태관리를 하려면 부모 컴포넌트에서 RecoilRoot로 감싸줘야한다. 내 경우에는 App.tsx
에서 감싸줬다.
import { RecoilRoot } from 'recoil';
<RecoilRoot>
<App {...f7params}>
<Views />
</App>
<RecoilRootPortal />
</RecoilRoot>
Atom은 컴포넌트가 구독할 수 있는 상태의 단위다.
key
와 deafult value
값을 지정할 수 있다.
export const itemAmountState = atom({
key: 'itemAmount',
default: 1,
});
내 경우, atoms/index.ts
에서 한번에 atom을 관리한다.
import { atom } from 'recoil';
export const lineItemState = atom<LineItem[]>({
key: 'lineItems',
default: [],
});
export const selectOptionState = atom({
key: 'selectOption',
default: 0,
});
Selector는 Recoil에서 함수나 파생된 상태를 나타낸다.
atom이 공유상태를 나타낸다면, Selector는 atoms 상태값을 동기 또는 비동기 방식을 통해 변환한다.
export const totalPriceState = selector({
key: 'totalPrice',
get: ({ get }) =>
get(lineItemState)
.map(({ total_price }) => total_price)
.reduce((prev: number, current: number) => prev + current, 0),
});
export const deliveryChargeState = selector({
key: 'deliveryCharge',
get: ({ get }) => (get(totalPriceState) >= 50000 ? 0 : 3000),
});
atom으로 관리하는 lineItem을 가져와서 total Price를 계산한다. totalPrice의 값이 50,000원 미만일 경우 배송비 3,000원이 추가되는 로직을 selector를 통해 관리한다.
사용법은 간단하다. 먼저 import하고
import { useRecoilState } from 'recoil';
setState하는 것처럼 똑같이 사용하면 된다.
const [lineItems, setLineItems] = useRecoilState(lineItemState);
값을 set할 필요가 없을때는 useRecoilValue
를 사용한다.
import { useRecoilValue } from 'recoil';
const totalPrice = useRecoilValue(totalPriceState);
세상 간단.
그냥 hook에서 state관리하는거랑 똑같다.
장바구니에 물건이 추가되고 삭제됨에 따라 총 금액에 변화가 있어야한다.
item 컴포넌트와 totalPrice컴포넌트는 다른 컴포넌트이기 때문에 상태관리를 전역으로 해줘야했다.
lineItem을 atom으로 관리하고 lineItem의 요소에 따라 totalPrice를 업데이트해줘야했기 때문에 totalPrice를 selector로 선언했다.
totalPrice 컴포넌트에서는 그냥 이렇게 가져다쓰기만 하면 된다.
장바구니에서 수량을 변경하면 총 금액이 바뀌고 총 금액이 5만원 미만일 경우 배송비가 추가된다.