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