오늘은 리코일을 공부했다.
공부했는데.. 공부해도 잘 모르겠다..
공부한 내용들과 실습한 것들을 정리해보겠다.


Recoil

페이스북에서 만든 React를 위한 상태 관리 라이브러리


Recoil을 쓰는 이유

기존의 리액트 상태관리 라이브러리 (ex. Redux)

기존의 리액트 상태관리 라이브러리는 Store 라는 곳에 상태를 저장한다.
여기서 Store는 외부 요인이기 때문에 리액트의 내부 스케줄러에 접근할 수가 없게 된다.

그리고 리액트에서도 동시성 모드(concurrent mode)가 등장하면서 리액트와 동시성 모드를 사용할 수 있는 방법을 고민하게 되었다.

또한, 리덕스와 같은 라이브러리는 Store를 구성하기 위해 많은 양의 코드를 작성해야 하고,
비동기 데이터 처리를 하기 위해서는 Redux-saga와 같은 별도의 라이브러리를 추가로 사용해 주어야 하는 불편함이 있다.

리액트 자체적으로 가지고 있는 Context API

반복되고 복잡한 업데이트를 하게 될 때 비효율적이다.

정적인 데이터 위주로 처리하거나 적은 업데이트가 일어나는 어플리케이션에는 적합하지만,
'결국 Context는 Flux와 같은 상태 관리 시스템을 대체할 수 없다'라고 페이스북 엔지니어 Sebastian Markbage는 이야기 했다.

Context의 경우 Provider-Consumer 구조로 상태를 주고 받는데,
Provider 하위의 모든 Consumer는 Provider 속성이 변경 될 때 마다 다시 렌더링이 된다.

여기에서 해당 Context를 구독하고 있는 모든 요소들이 렌더링이 되기 때문에 상당히 비효율적이다.

Recoil 은 ?

리코일은 방향이 있는 그래프가 직교한 형태로 우리의 리액트 트리 구조에 붙어있게 만들어 준다.

이 그래프의 루트에서부터 상태 변화가 일어나는데 이 루트를 아톰(atom)이라고 한다.
그리고 이 과정은 순수함수를 통해서 일어나며 이를 선택자(selector)라고 한다.

이러한 접근을 통해 리코일은 다음과 같은 특징을 가질 수 있다.

  • 보일러플레이트가 없는 API 이며 리액트 지역 상태로서 단순한 get/set 인터페이스로 상태를 공유할 수 있다.
  • 동시성 모드와 양립할 수 있는 가능성이 있으며 새로운 리액트의 특성이 가능하게 한다.
  • 상태 정의는 증가하면서 분산되어서 코드 스플리팅이 가능하다.
  • 상태는 컴포넌트의 변경 없이 파생된 상태로 대체가 될 수 있다.

언제 사용할까 ?

바로 하위컴포넌트는 props로 전달하면 되지만 컴포넌트가 복잡해지면 전달해지기 어렵기 때문에 리코일 사용

useState 값을 부득이하게 다른 컴포넌트에서 써야할때

서버와 통신하는게 아닌 리덕스로 데이터를 저장해야될때

팝업, isLogin, floating box 등등

  • 팝업 ?
    • fixed로 바탕화면에 상시 띄우는 것
    • (상시 앱에 두고) atom에 리코일로 팝업상태와 언팝업 구독해놓으면 사용 가능
    • 여러상황에서 쓰기 위해 앱에 넣어놓고 필요할때마다 꺼내씀
    특정 이벤트를 실행했을때 팝업상태를 트루로 만들면,
    스타일에서 팝업을 보이게 만들고 아님 없애게 만듦

Atom

아톰은 상태의 단위이다.

  • 업데이트와 구독이 가능하다.
  • 아톰이 업데이트 되면 각각을 구독하고 있는 컴포넌트들은 새로운 값으로 리렌더링이 일어난다.
  • 런타임 환경에서 생성될 수가 있다.
  • 리액트의 지역 컴포넌트 상태에서 사용된다.
  • 만약 같은 아톰이 여러 컴포넌트에 사용되면, 그 모든 컴포넌트들은 그 상태를 공유한다.

아톰은 유니크 key 값을 필요로 하는데,
이 키는 디버깅, 지속, 모든 아톰의 지도를 보기 위한 고급 API를 위해서 사용된다.

같은 키 값을 두 개의 아톰이 같이 들고 있으면 에러가 발생하므로 유의해야 한다.

컴포넌트에서 아톰을 읽고 쓰기 위해서는 useRecoilState라는 훅을 사용해야 한다.
리액트의 useState와 비슷하지만, 차이가 있다면 이제 상태는 컴포넌트 간에 공유가 가능하다.


사용 방법 (CRUD)

아톰 함수에 객체 하나를 담아서 만든다.

그리고 그 안에 key, default 가 있어야 한다.

  • key : 고유한 이름이어야 함. 보통 변수명과 일치.
  • default : 원하는 값을 넣어줌

출력할 때는 useState 쓰는 것처럼 useRecoilState 로 getter, setter를 선언한다.
(객체 지향에서 많이 쓴다)

--> const [ getter, setter ] = useRecoilState( 선언했던 변수명 )
: default 안에 있던 값이 초기값으로 들어감
: [ ] 배열로 넣어놨으면 배열이 됨 (map 돌리기 가능)

setList를 바꿀 때는 (함수형에서는) 불변성을 지켜야 한다.
기존 값을 건드리면 안되므로 current => ...current, 등으로 작성한다.

원래 상태로 돌리는 것 = useRestRecoilState( 돌릴 변수명 );

const resetTest = useRestRecoilState( 변수명 );

cosnt reset = (e) => {
 resetTest();
 
<button onClick={reset}>리셋</button>
  • 데이터 조회만(getter) 하고 싶은 경우 = RecoilValue
  • setter 만 쓰고 싶은 경우 = useSetRecoilState

Selector(선택자)

선택자는 순수 함수이고 아톰이나 다른 선택자를 입력값으로 받는다.

이러한 상위 아톰이나 선택자가 업데이트 되면 선택자 함수는 다시 계산될 것이다.
컴포넌트들은 아톰처럼 선택자를 구독할 수 있으며, 선택자가 변화하면 리렌더링이 일어난다.

선택자는 상태에 기반하여 파생된 데이터를 계산할 때 사용된다.
최소한의 상태가 아톰에 저장되어 있고 효율적으로 함수에 의해 계산되기 때문에 취약한 상태를 가지는 것을 피할 수 있다.

선택자가 계속하여 어떤 컴포넌트가 필요로 하고 어떠한 상태에 그들이 의존하는지를 추적하기 때문에 이러한 함수적 접근은 매우 효율적이다.

예 ) data의 카테고리에 "음식" 만 뽑아서 보고 싶은 경우 ?
: data를 가져와서 리스트를 뿌려주는게 아니라,
selector를 가져오는 것 !

선택자는 selector 함수를 사용하여 정의하며,

내 데이터를 원하는 형태로 가공해서 출력, 수정하고 싶을 때 사용한다. (리팩토링 할때 유용하게 씀)

데이터를 export import 해서 불러와 사용한다.

selector( { } ) 괄호 안에 중괄호를 사용하며,

key , get, set
--> getter 와 setter 가 존재한다.

  • getter : useRecoilState의 list
    • get의 return 값이 들어감
    • get 함수는 data를 가져올 수 있음
  • setter : useRecoilState의 setList

get 함수

여기서 oldList = data를 가져오는 것

cat 함수를 만들어서 필터링 시키는것

set 함수

set, get, reset 3가지를 가지고 있다.

newValue
: selector 의 setList를 사용했을때 추가할 값이 ref.current.value 일 경우
--> newValue 로 들어감

: set에서 newValue로 값을 가져오고
: get으로 데이터를 가져오고
: set으로 올드리스트를 넣어주고, 값을 어떻게 바꿔줄건지 적기

1개의 댓글

comment-user-thumbnail
2022년 7월 15일

감사해요! 덕분에 참고해서 TIL 잘 적었어요!

답글 달기