Home React | Recoil (230529 추가)
Post
Cancel

React | Recoil (230529 추가)

React

목차

  1. Recoil이란 무엇인가?
  2. Recoil에서 Loadable의 개념
  3. Recoil에서 비동기로 데이터를 받아올 때 state 관리법
  4. Recoil에서 로딩,성공,에러 처리방법
  5. Redux와 Recoil 비교


1. Recoil이란 무엇인가?

: 페이스북에서 출시한 React 만을 위한 상태 관리 라이브러리

1. Recoil의 특징

  • React 문법 친화적
    : 전역 상태 값도 React의 state처럼 간단한 get/set 인터페이스로 사용할 수 있는 boilerplate-free API를 제공함
  • React와 개발 방향성이 같음
    : 동시성 모드(Concurrent Mode)를 비롯한 다른 새로운 React의 기능들과의 호환 가능성도 가짐
  • 비동기 처리를 간단하게 할 수 있음
    : 추가 라이브러리 없이 recoil만으로 가능함
  • 내부적으로 캐싱이 됨
    : 동일한 atom 값에 대해 내부적으로 메모이즈된 값을 반환하여 속도가 빠름

* 단어 정리

boilerplate : 변형이 거의 없는 여러 장소에서 반복되는 코드의 섹션(‘별 수정 없이 반복적으로 사용되는 코드’를 자동으로 생성해주는 것)

2. Recoil의 진행 순서

recoil1
recoil2
recoil3


: 기존 리액트 철학인 탑→다운에서 작은 상태들을 쌓아 바텀→업 스타일로 상태관리 철학을 변경함

  1. 바닥부터 조합
  2. 아톰을 조합해 더 큰 상태를 만듦
  3. 비동기 상태도 조합이 가능함

3. Recoil의 장점

  1. react와 업데이트 방향이 같음
  2. 내부적으로 자동적으로 캐싱되어 빠름(side-effect 존재)
  3. 상태를 분산적으로 두어 코드 스플리팅이 가능

4. Recoil의 단점

  1. 안정성

    • UNSTABLE한 API
    • 2022.07 현재 최신 버전이 0.7.4
    • 저장소명이 facebookexperimental/Recoil
  2. 개발자 도구의 부재

    • useRecoilSnapshot()가 존재하지만 UNSTABLE
  3. 부족한 레퍼런스

2. Recoil에서 Loadable의 개념

: suspense 를 사용하지 않고 비동기를 제어 해야 하는 경우를 위해 useRecoilValueLoadable 와 useRecoilStateLoadable 함수를 지원함

→ 위 함수를 호출하면 아래와 같은 2개의 값을 반환하게 됨(두가지는 setter 포함 유무의 차이)
→ 공식문서에 따르면 Loadable은 최신 상태에 접근하기 위한 도우미 메서드를 가지고 있으나 이러한 API는 아직 불안정하다고 함

  • loadable 메소드 리스트

    • getValue() : React Suspense와 Recoil selectors의 시맨틱에 매치되는 값에 접근하기 위한 메서드
    • toPromise() : selector가 resolve되면 resolve될 Promise 를 리턴
    • valueMaybe() : 가능하면 값을 리턴하며 다른 경우에는 undefined 를 리턴
    • valueOrThrow() : 가능하면 값을 리턴하거나 Error
    • map() : Loadable의 값을 변형하기 위한 함수를 받으며 새로운 Loadable을 변형된 값과 함께 리턴


  • Loadable 을 통한 상태
    • Lodable 객체
      • state: slector의 상태를 반환. hasValue, hasError, loading 값 중 하나를 String으로 반환함
      • contents: Loadable이 나타내는 값
        • state가 hasValue이면 실제 값
        • state가 hasError이면 throw된 Error객체
        • state가 loading이면 Promise
class Loadable 예시
1
2
3
4
5
6
7
8
9
10
11
function UserInfo({userID}) {
  const userNameLoadable = useRecoilValueLoadable(userNameQuery(userID));
  switch (userNameLoadable.state) {
    case 'hasValue':
      return <div>{userNameLoadable.contents}</div>;
    case 'loading':
      return <div>Loading...</div>;
    case 'hasError':
      throw userNameLoadable.contents;
  }
}

3. Recoil에서 비동기로 데이터를 받아올 때 state 관리법

: Recoil에서의 비동기 처리는 React의 일반 state의 흐름을 벗어나지 않고 거의 동일하게 흘러감

  1. Component Mounts
  2. Fetch Data
  3. Update state with fetched data
  • RecoilRoot

    • 컴포넌트에서 Recoil state를 사용하기 위해서는 recoil 상태를 사용하고자 하는 컴포넌트의 부모에 RecoilRoot를 선언해주어야 함
    • RecoilRoot는 여러 개를 선언할 수 있음
    RecoilRoot 예제
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    // App.js
    import React from 'react';
    import { RecoilRoot } from 'recoil';
    
    const App = () => {
      return (
        <RecoilRoot>
          <CharacterCounter />
        </RecoilRoot>
      );
    }
    


  • Atoms

    • state의 단위이며 업데이트와 구독이 가능
    • atom 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독함 → atom에 어떤 변화가 있다면 그 atom을 구독하는 모든 컴포넌트가 리렌더링됨
    • key와 default값을 필수로 선언해줘야함
      • key : 내부적으로 atom을 식별하는 데 사용되는 고유한 문자열
        전역적으로 고유한 값을 가져야 하므로 네이밍 시 $와 같은 구분자를 붙여 사용하기도 함
      • default : atom의 초깃값
        다양한 타입을 사용할 수 있으며, 동일한 타입의 값을 나타내는 다른 atom이나 selector도 가능함
    Atoms 예제
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    // atoms.js
    import { atom } from "recoil";
    
    export const countState = atom({
      key: "countState", // 전역적으로 고유한 값
      default: 0 // 초깃값
    });
    
    // Counter.js
    import React from "react";
    import { useRecoilState, useResetRecoilState } from "recoil";
    import { countState } from "../states/atoms";
    
    export const Counter = () => {
      const [count, setCount] = useRecoilState(countState);
      const resetCount = useResetRecoilState(countState);
    
      const increase = () => {
        setCount(count + 1);
      };
    
      const reset = () => {
        resetCount();
      };
    
      return (
        <div>
          <h2>{count}</h2>
          <button onClick={() => increase()}>+</button>
          <button onClick={() => reset()}>reset</button>
        </div>
      );
    };
    
    
    • 컴포넌트에서 atom을 읽고 쓸 수 있게 하기 위해서는 useRecoilState()를 사용
    • React의 useState()와 상당히 유사한 형태(기본값 대신 Recoil state를 인자로 받는 다는 것을 제외하면!)
    • useRecoilState()는 상태값과, setter함수를 리턴 → 이 hook은 암묵적으로 state를 구독함(atom 값이 변경되면 컴포넌트가 자동적으로 리렌더링)


  • Selectors

    • 전역 상태 값을 기반으로 어떤 계산을 통해 파생된 상태(derived state)를 반환하는 순수함수
    • 최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지함
      (ex. todolist와 filter된 todolist 여기서 filter된 todolist를 selector를 활용하면 좋음)
    • 메모리 누수 주의 필요
      (atom의 값이 같으면 내부적으로 반환 값을 메모이즈 하고 있어 캐싱된 값을 반환하기 때문에 요청을 줄이고 빠르게 값을 반환할 수 있지만 메모리 문제 발생)
    • get함수
      • 파생된 상태의 값을 평가하는 함수
      • get함수만 제공되면 Selector는 읽기만 가능한 RecoilValueReadOnly 객체를 반환
      • get 매개변수를 이용하여 atom이나 다른 selector를 참조할 수 있음
    • set 함수
      • 이 속성이 설정되면 selector는 쓰기 가능한 상태를 반환
      • 첫번째 매개변수로 콜백 객체와 새로 입력 값이 전달됨

4. Recoil에서 로딩,성공,에러 처리방법

: 비동기 요청은 일반적으로 로딩, 성공, 실패 이렇게 세 가지 상태를 가짐

  • 로딩 : suspense를 통해 로딩상태를 나타냄
  • 실패 : Error Boundary(하위 컴포넌트 트리의 어디에서든 에러를 리포트하며 애플리케이션 중단 대신 fallback UI를 보여주는 React 컴포넌트) → 렌더링 중 발생하는 에러, React와 관련된 에러를 캐치

→ useRecoilValueLoadable()을 이용한 비동기 처리로 렌더링중 상태를 확인하고 Loadable 객체를 반환
→ switch문을 이용하여 imageUrlLoadable객체의 state값에 따라 로딩중, 에러발생, 정상응답에 대한 케이스를 분리(loadable 참고)

5. Redux와 Recoil 비교

  • Redux
    • 커뮤니티 지원
      : 대규모 사용자 커뮤니티가 구축되어 있음 → Github에서 가장 별을 많이 받은 리액트 상태 관리 라이브러리
    • 성능 향상
      : 성능 최적화를 보장하여 필요할 때만 연결된 컴포넌트를 다시 렌더링
    • Redux를 통한 상태 예측
      : 이전 상태를 왔다 갔다 하며 실시간으로 결과를 확인 할 수 있음
    • 로컬 스토리지를 통한 상태 지속성
      : 앱의 상태 중 일부를 로컬 스토리지에 유지하고 새로고침 후 복원할 수 있음
    • 서버 사이드 렌더링
      : 서버 요청에 대한 응답과 함께 앱의 상태를 서버로 전송하여 앱의 초기 렌더링을 처리 할 수 있음
    • 유지보수성
      : 코드를 설계하는 방법에 대해 엄격하기 때문에 함께 협업을 할 때 어플리케이션의 구조를 쉽게 이해할 수 있음
  • Recoil
    • 리액트스러운 접근과 단순함
    • 쉬운 러닝 커브
      : 이해하기 쉬운 Atom과 Selectors라는 개념
    • 앱 전체적인 상태 관찰
      : Recoil도 앱 전체 상태 관찰을 잘 처리





출처

Recoil 공식문서
Recoil: React를 위한 상태 관리 라이브러리
Recoil 비동기통신(Suspense, Loadable)
React-boilerplate란?
recoil과 비동기 데이터 호출 (+ 선언적 프로그래밍)
2021년 React 상태 관리 라이브러리 전쟁 : Hooks, Redux, Recoil
Recoil 에서 Selector 기능 get, set 사용법

This post is licensed under CC BY 4.0 by the author.