Mobx는 어느정도 사용할줄 알게되어서 가장 악명높은Redux를 할려고 했었는데. . .
분명 좀 어렵겠지 했지만 공부하면 할수록 너무 어려워서 결국Recoil찍먹 결정! 😊
Recoil은 페이스북에서 만든 React전용 상태 관리 라이브러리 이다!
상태관리를 위한 라이브러리는 대표적으로 Redux, Mobx등 여러가지가 이미 사용되고있다.
여전히 잘 사용되고있고 문제없는 좋은 라이브러리인데, 왜 Recoil이 나오게 된걸까?
➡ Redux나 Mobx같은 라이브러리는 React전용 상태 관리 라이브러리가 아니기 때문에
React 내부 스케쥴러에 접근할 수 없고, 작은 기능하나 만드는데에도 긴 코드 를 써야하는 번거로움이 있다🤔
장점
- React 자체 라이브러리
↪ Redux, Mobx와 다르게 Recoil은 React의 전용 상태관리 lib이기 때문에
↪ React 내부에서 접근이 가능하며React 동시성 모드Suspense등이 쉽게 지원된다!
- 적은 코드라인과 보일러 플레이트
↪Redux를 공부했을 때 무언가 작은 것 하나 만들어 보려하면 수많은 보일러 플레이트가 필요했다.
↪Recoil은 훨씬 적은 코드라인으로 가능하지롱 😁😁😁
- 공부하기가 쉽다!
↪ 지극히 개인적인 의견이긴 하지만 Redux, MobX를 공부할 때 보다 훨씬 쉬웠다!
단점
- Hooks
↪ Recoil의 API는 대부분Hooks형태로 있어서Hooks가 생소한 사람들에게는 러닝커브가 조금 있을 수 있다.
- 라이브러리 개발중
↪ 아직 페이스북에서 열심히 개발중인 Lib라서 실서비스까지 보고 쓰기에는 다소 힘들 수 있다.
- 디버깅 도구
↪ 위에서 말했듯이 라이브러리가 아직 개발중이기 때문에 디버깅도구의 지원이 미미하다 😂
Atom은 하나의 상태라고 볼 수 있다. 이 값은 컴포넌트에서 구독할 수 있고,
Atom의 값이 바뀌게 되면 해당 Atom을 구독하고있던 모든 컴포넌트들이 리렌더링 된다.
Redux에서는 render단위로 state를 구성했는데, Atom은 이런 reducer 단위가 아닌 더 잘게 쪼개진 state 단위로 상태를 관리하게 된다.
Atom을 생성하기 위해선 어플리케이션에서 고유한 키 값과 기본 값을 설정해줘야한다.
➡ 기본 값은 정적인 값, 함수 심지어 비동기 함수까지도 지원 예정이라고 한다.)
Atom 예시
↪key는 nameState,기본 값은 Son Min Jae라고 주었다.
selector는 atom의 상태에 의존하는 동적인 데이터를 생성한다.
selector에서는 get함수(필수)를 통해 atom정보들을 1개 이상 가져올 수 있습니다.
이를 통해 atom을 조합해 새로운 데이터를 생성할 수 있습니다.
물론 atom의 정보가 바뀌면 해당 atom을 의존하는 selector도 자동으로 리렌더링 됩니다.
또한 Selector에서 한 개 이상의 atom정보를 업데이트 하도록 set함수(선택)을 받을 수 있습니다.
get 함수만 제공되면 Selector는 읽기만 가능한 RecoilValueReadOnly 객체를 반환하고
set 함수도 제공되면 Selector는 쓰기 가능한 RecoilState 객체를 반환합니다.
Selector 예시
↪ get만 했어용
![]()
컴포넌트에서 atom과 selector를 위해 쓰는 함수들은 크게 4가지로 분류됩니다.
1.
useRecoilState➡ atom이나 selector의 상태와 setter함수를 받는다.
2.useRecoilValue➡ atom이나 selector의 상태만 받는다.
3.useSetRecoilState➡ atom이나 selector의 setter함수만 받는다.
4.useResetRecoilState➡ atom이나 selector의 상태를 기본 값으로 지정하는 함수를 받는다.
import { nameState } from './somewhere';
// useRecoilState => 상태와 setter함수 둘다 가지고 오기
const NameInput = ( => {
const [name, setName] = useRecoilState(nameState);
const onChange = (event) => {
setName(event.target.value);
};
return (
<input type="text" value={name} onChange={onChange} />
<div> Name: {name} </div>
);
}
// useRecoilValue => 상태만 가지고오기
const OtherComponentWithName = () => {
const name = useRecoilValue(nameState);
return <div> {name} </div>;
}
// useSetRecoilState => setter함수만 가져오기
const OtherComponentThatSetName = () => {
const setName = useSetRecoilState(nameState);
return <button onClick={() => setName('Min Jae')}> Set Name </button>;
}
// useResetRecoilState => atom이나 selector의 상태를 기본 값으로 바꿔주는 함수
const OtherComponentThatResetName = () => {
const onClickBtn = useResetRecoilState=(nameState);
return <button onClick={() => onClickBtn()}> Reset </button>;
}
캐싱지원
selector를 통해 비동기 통신을 할 때 가장 큰 장점중 하나입니다.
자체적으로 캐싱을 지원하기 때문에 같은 액션에 있어서 캐싱된 결과를 바로 보여주기 때문에
퍼포먼스 면에서도 훨씬 유리 합니다.
비동기 제어
Recoil에서는Suspense를 사용하지 않고 비동기를 제어할 수 있습니다.
바로useRecoilValueLoadable과useRecoilStateLoadable을 쓰는거죠 😁
useRecoilValueLoadable➡ 현재 비동기 작업의 상태 값을 받아온다.useRecoilStateLoadable➡ 현재 비동기 작업의 상태 값 과 setter함수를 받아온다.
Loadable을 통한 상태
state➡ 비동기 상태를 나타내며hasValue(값이 존재),loading(로딩중),hasError(에러발생)이렇게 3가지 상태가 존재합니다.
contents➡ 비동기 통신의 결과 값 입니다.
위에서 말한state별로 값이 달라지는데요hasValue일때는value로loading일때는Promise로hasError이면Error객체로 됩니다.↪
Redux에서는 각state에 대한 비동기 상태를 별도로 가져야 하지만Recoil의selector는 비동기 상태에 대한 정보는 담고 있지 않아도useRecoilLoadable에서 지원해줌으로 훨씬 깔끔합니다.
Loadable 예시
import { useRecoilState, useRecoilValueLoadable } from 'recoil';
import {delayCountState, delay1SecSelector} from './recoil/delayCount';
function DelayCount() {
const delay1Sec = useRecoilValueLoadable(delay1SecSelector);
// delay1Sec라는 변수에 useRecoilValueLoadable로 delay1SecSelector의 상태 값만 받아오고
const [delayCount, setDelayCount ] = useRecoilState(delayCountState);
// useRecoilState로 delayCountState의 상태와 setter함수를 받아온다.
if(delay1Sec.state === 'loading') {
// loadable으로 받아온 변수의 상태가 loading이면 로딩중이라고 띄워주기
return (<div>로딩중 입니둥 ~ </div>);
}
return (
<>
<h3>캐싱된 selector 값 </h3>
<p>{delay1Sec.contents}</p>
<button onClick = {() => setDelayCount(delayCount + 1)}>증가</button>
<button onClick = {() => setDelayCount(delayCount - 1)}>감소</button>
</>
);
};
export default DelayCount;
Redux가 너무 어려워서 Recoil로 방향을 틀어서 공부를 하고있습니다.
Recoil은 러닝커브도 낮고 코드도 간결하면서 번거로움이 적어 제 취향에 너무 잘 맞는 라이브러리인것 같아요! 😆
아직 AtomFamily나 SelectorFamily Selector-set 등 여러가지 개념들이 남았으니까 추후에 더 올리도록 할게요!
감사합니다. 😎
참고한 문서 및 블로그들
VELOG1 / VELOG2 / Blog1 / Blog2 / Blog3 / Blog4 / Blog5 / Blog6Blog7 / Recoil