리액트 상태관리 라이브러리 역사와 Recoil

 

1. 왕위 부재

한동안 기본적인 context, prop, state가 유일한 상태관리 방법이었음.
  1. 페이스북에서 Flux 아키텍처를 발표함. 근데 공개된 코드는 없었음.
  1. 페이스북에서 디스패처만 공개하고 나머지 구현에 대한 코드는 없음.

3. Flux 구현체의 등장

  1. 2015년 Redux, MobX 등 Flux 아키텍처를 구현한 라이브러리들이 공개되기 시작함.
  1. 이들은 리액트에 종속된 것이 아닌 독립된 라이브러리임.
  1. 여러 라이브러리들이 더 나왔지만 ReduxMobX가 양대산맥을 지켜왔음. (여러가지 미들웨어들도 한몫함)

4. Context API

test1, setTest1 test2, setTest2 test3, setTest3
사실 전역상태관리도 되고, 리액트도 잘 지원하는 Context API라는 것이 있긴 했음.
하지만, 변화한 상태와 관련된 컴포넌트만 re-render되는 것이 아니라, context 자체를 구독하고 context 내의 어떤 상태라도 변화하면 해당 context를 구독한 모든 컴포넌트들이 re-render된다는 이슈가 있다.
따라서
  1. 상태가 많다면 불필요한 re-render를 줄이고자, 데이터마다 Context를 만들고 Provider를 제공해서 씀.
    1. ⇒ 너무 많은 Provider가 중첩됨...ㅋㅋㅋㅋ (번거롭고, 코드 보기도 안좋아..!)
  1. 상태가 적어서 re-render 되어도 부담이 적은 것들만 묶어서 관리
페이스북 공식 문서 발췌. 테마와 유저상태만 있는데도 Provider 2개를 감싸야함
페이스북 공식 문서 발췌. 테마와 유저상태만 있는데도 Provider 2개를 감싸야함
발표자 회사에서 쓰는 결제모듈 트리. Context Provider가 엄청 중첩된 것을 볼 수 있다.
발표자 회사에서 쓰는 결제모듈 트리. Context Provider가 엄청 중첩된 것을 볼 수 있다.
따라서 별도의 라이브러리의 도움 없이 Context API 만으로 상태관리를 하기에는 무리가 있었다.
( constate와 같은 서드파티 라이브러리가 이것을 편하게 도와주긴 함. )

5. Recoil 탄생

  1. 페이스북이 2020.5월에 React EU에서 발표함
  1. React를 "더 잘" 지원할 목적으로 작성
  1. 다른 상태관리 라이브러리는 범용 라이브러리인 반면에, Recoil은 React를 기반으로 작성된 React전용 라이브러리임.

데이터 플로우

Recoil의 데이터 흐름은 Data-flow 그래프로 표현됨
데이터 플로우 그래프는 계산이나 데이터의 흐름을 노드엣지로 표현하는 그래프인데, 머신러닝 해봤으면 들어봤을 것.
Recoil에서는 AtomSelector를 따라서 흘러서 React 컴포넌트로 흘러감.
notion image

아톰(Atom)

  • 하나의 상태 데이터
  • keydefault value만 설정하면 돼서 굉장히 단순함.

셀렉터(selector)

두가지 의미를 가짐
  1. 아톰에서 파생 된 데이터 조각
  1. 데이터를 반환하는 순수함수
notion image

[실습] 간단한 카운터 예시

redux와는 어떻게 다른거지??
recoil을 통해 보일러플레이트 코드가 확 줄어서 훨씬 깔끔하고 간단하게 코드를 작성할 수 있다.
selector와 dispatch보다, 그냥 useState 훅 처럼 사용하기 때문에 코드가 좀 더 직관적임.

1. App.jsx 파일에 <RecoilRoot>를 추가한다.

RecoilRoot

하위에 있는 모든 recoil 데이터의 루트가 된다.
내부적으로는 react의 context api를 사용하고 있고, store를 선언해서 context에 내려주는 역할을 함
리덕스를 쓸 때는 직접 store를 만들어야하는데, recoil에서는 RecoilRoot만 선언하면 알아서 스토어 만들어짐.
RecoilRoot는 중첩해서 쓸 수도 있음.
중첩할 경우 atoms와 selectors는 가장 가까운 RecoilRoot에 선언된 store를 사용함
어쨋든 데이텉를 저장하고 여러 컴포넌트에서 공유하려면 RecoilRoot로 감싸줘야한다는 점만 기억하자.
import React from 'react'; import { RecoilRoot } from 'recoil'; import './styles.css'; export default function App() { return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> <RecoilRoot></RecoilRoot> </div> ); }

2. Counter 컴포넌트 작성

  1. Counter.jsx 파일을 만들고, 빈 Counter 컴포넌트를 작성함
  1. App.jsx파일에 Counter 컴포넌트를 추가함.
    1. notion image
  1. Counter.jsx에 count 상태 아톰을 선언함
    1. ( 카운터라서 0으로 뒀지만, default 값에는 객체, 리스트 같은 복잡한 것들도 전달 가능 )
  1. count 아톰을 사용하기 위해 useRecoilState 훅을 호출함.
  1. 화면에 카운터를 표시하고 카운터를 증가/감소하는 버튼을 추가함
    1. notion image
 

[실습] 예제2 - 셀렉터 사용하기 (짝인지 홀인지 알려주는 것)

사용할 상태 아톰의 key와 / get, set, reset 을 이용해서 파생 데이터를 만들어 반환할 수 있음.
notion image
notion image

[실습] 예제3. 서버 API 연동

💡
비동기 데이터 처리는 recoil의 단순함의 장점이 가장 잘 보이는 부분이라고 생각함.
notion image
selector의 get에 async 함수가 선언되었다.
selector의 get에 async 함수가 선언되었다.
notion image
가져오기 전까지에 대한 처리가 없으므로, 에러가 나는 것이 정상임.
notion image
suspense는 컴포넌트를 완전히 렌더링할 수 있기까지 렌더링을 멈춰두는 기능임.
recoil의 목적 중에 react를 좀 더 잘 구현하려고 하는 부분이 있었음.
suspense는 향후에 도입될 동시성 모드 기능의 일부임.
notion image
fallback에는 기다리는 동안 보여줄 컴포넌트를 전달하면 됨.
동기식 데이터와 비동기식 데이터를 크게 다르지 않은 형태로 다룰 수 있다는 장점도 있음.
 
notion image
atom과 selector는 같은 hook을 사용하지만, loadable은 전용 api를 써야함.
use...loadable 관련 훅들이 몇가지 있음.
notion image
suspense는 error 처리를 하려면 try-catch를 별도로 해줘야하는데, lodable 훅을 이용하면 로딩성공실패를 전부 커버할 수 있음.
redux에서는 비동기 처리를 위해 별도의 서드파티 라이브러리가 필요했고, mobX도 로딩상태를 표현하기 위해서 사용자가 별도로 상태처리를 해줘야하는 번거로움이 있었음.
notion image
 

추천!!! (이게 recoil의 최종 template이 될듯)

notion image
 
notion image
 
notion image
 
notion image
검색어별로 자동으로 결과를 캐시해두므로, 별도의 캐싱 작업을 할 필요가 없다.
그 이유는 검색어를 atom에서 가져오기 때문에 가능함.
아래에서 좀 더 자세히 살펴보자.
notion image
selectro안에서 사용한 atom에는 자동으로 의존성이 걸림
  1. 의존된 아톰의 상태 값이 변경될 때마다 자동으로 파생된 selector의 값도 변하게됨.
  1. 의존성 걸린 값이 모두 같으면 동일한 결과를 반환함
  1. 내부의 코드를 보면 반환값을 memoize하고있음.
한번 검색한 결과는 서버에서 가져오지 않고 캐시에서 가져오므로 더 빠르게 가능.
 
notion image
훅으로만 지원되므로 클래스형으로는 작성할 수 없다는 단점이 있긴하지만, HOC 패턴을 통해 충분히 극복 가능