Recoil 찍먹

Clzzi·2021년 4월 22일
1

Recoil

목록 보기
1/2
post-thumbnail

Mobx는 어느정도 사용할줄 알게되어서 가장 악명높은 Redux 를 할려고 했었는데. . .
분명 좀 어렵겠지 했지만 공부하면 할수록 너무 어려워서 결국 Recoil 찍먹 결정! 😊

Recoil 뭘까?

Recoil은 페이스북에서 만든 React전용 상태 관리 라이브러리 이다!

Recoil 어쩌다 개발 되었을까?

상태관리를 위한 라이브러리는 대표적으로 Redux, Mobx등 여러가지가 이미 사용되고있다.
여전히 잘 사용되고있고 문제없는 좋은 라이브러리인데, 왜 Recoil이 나오게 된걸까?

ReduxMobx같은 라이브러리는 React전용 상태 관리 라이브러리가 아니기 때문에
React 내부 스케쥴러에 접근할 수 없고, 작은 기능하나 만드는데에도 긴 코드 를 써야하는 번거로움이 있다🤔

Recoil의 장단점!

장점

  • React 자체 라이브러리
    ↪ Redux, Mobx와 다르게 Recoil은 React의 전용 상태관리 lib이기 때문에
    ↪ React 내부에서 접근이 가능하며 React 동시성 모드 Suspense 등이 쉽게 지원된다!

  • 적은 코드라인과 보일러 플레이트
    Redux를 공부했을 때 무언가 작은 것 하나 만들어 보려하면 수많은 보일러 플레이트가 필요했다.
    Recoil은 훨씬 적은 코드라인으로 가능하지롱 😁😁😁

  • 공부하기가 쉽다!
    ↪ 지극히 개인적인 의견이긴 하지만 Redux, MobX를 공부할 때 보다 훨씬 쉬웠다!

단점

  • Hooks
    ↪ Recoil의 API는 대부분 Hooks형태로 있어서 Hooks가 생소한 사람들에게는 러닝커브가 조금 있을 수 있다.

  • 라이브러리 개발중
    ↪ 아직 페이스북에서 열심히 개발중인 Lib라서 실서비스까지 보고 쓰기에는 다소 힘들 수 있다.

  • 디버깅 도구
    ↪ 위에서 말했듯이 라이브러리가 아직 개발중이기 때문에 디버깅도구의 지원이 미미하다 😂

Atom

Atom은 하나의 상태라고 볼 수 있다. 이 값은 컴포넌트에서 구독할 수 있고,
Atom의 값이 바뀌게 되면 해당 Atom을 구독하고있던 모든 컴포넌트들이 리렌더링 된다.
Redux에서는 render단위로 state를 구성했는데, Atom은 이런 reducer 단위가 아닌 더 잘게 쪼개진 state 단위로 상태를 관리하게 된다.

Atom을 생성하기 위해선 어플리케이션에서 고유한 키 값과 기본 값을 설정해줘야한다.
➡ 기본 값은 정적인 값, 함수 심지어 비동기 함수까지도 지원 예정이라고 한다.)

Atom 예시
keynameState, 기본 값Son Min Jae라고 주었다.

Selector

selector는 atom의 상태에 의존하는 동적인 데이터를 생성한다.
selector에서는 get함수(필수)를 통해 atom정보들을 1개 이상 가져올 수 있습니다.
이를 통해 atom을 조합해 새로운 데이터를 생성할 수 있습니다.

물론 atom의 정보가 바뀌면 해당 atom을 의존하는 selector도 자동으로 리렌더링 됩니다.
또한 Selector에서 한 개 이상의 atom정보를 업데이트 하도록 set함수(선택)을 받을 수 있습니다.

get 함수만 제공되면 Selector는 읽기만 가능한 RecoilValueReadOnly 객체를 반환하고
set 함수도 제공되면 Selector는 쓰기 가능한 RecoilState 객체를 반환합니다.

Selector 예시
↪ get만 했어용

Recoil 상태와 상태 변경 함수

컴포넌트에서 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의 특이점

캐싱지원
selector를 통해 비동기 통신을 할 때 가장 큰 장점중 하나입니다.
자체적으로 캐싱을 지원하기 때문에 같은 액션에 있어서 캐싱된 결과를 바로 보여주기 때문에
퍼포먼스 면에서도 훨씬 유리 합니다.

비동기 제어
Recoil에서는 Suspense를 사용하지 않고 비동기를 제어할 수 있습니다.
바로 useRecoilValueLoadableuseRecoilStateLoadable을 쓰는거죠 😁

  • useRecoilValueLoadable ➡ 현재 비동기 작업의 상태 값을 받아온다.
  • useRecoilStateLoadable ➡ 현재 비동기 작업의 상태 값 과 setter함수를 받아온다.

Loadable을 통한 상태

  • state ➡ 비동기 상태를 나타내며 hasValue(값이 존재) , loading(로딩중), hasError(에러발생) 이렇게 3가지 상태가 존재합니다.

  • contents ➡ 비동기 통신의 결과 값 입니다.
    위에서 말한 state별로 값이 달라지는데요 hasValue일때는 valueloading일때는 PromisehasError이면 Error 객체로 됩니다.

Redux에서는 각 state에 대한 비동기 상태를 별도로 가져야 하지만 Recoilselector는 비동기 상태에 대한 정보는 담고 있지 않아도 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은 러닝커브도 낮고 코드도 간결하면서 번거로움이 적어 제 취향에 너무 잘 맞는 라이브러리인것 같아요! 😆
아직 AtomFamilySelectorFamily Selector-set 등 여러가지 개념들이 남았으니까 추후에 더 올리도록 할게요!
감사합니다. 😎

참고한 문서 및 블로그들
VELOG1 / VELOG2 / Blog1 / Blog2 / Blog3 / Blog4 / Blog5 / Blog6Blog7 / Recoil

0개의 댓글