React
목차
- Recoil이란 무엇인가?
- Recoil에서 Loadable의 개념
- Recoil에서 비동기로 데이터를 받아올 때 state 관리법
- Recoil에서 로딩,성공,에러 처리방법
- Redux와 Recoil 비교
1. Recoil이란 무엇인가?
: 페이스북에서 출시한 React 만을 위한 상태 관리 라이브러리
1. Recoil의 특징
- React 문법 친화적
: 전역 상태 값도 React의 state처럼 간단한 get/set 인터페이스로 사용할 수 있는 boilerplate-free API를 제공함 - React와 개발 방향성이 같음
: 동시성 모드(Concurrent Mode)를 비롯한 다른 새로운 React의 기능들과의 호환 가능성도 가짐 - 비동기 처리를 간단하게 할 수 있음
: 추가 라이브러리 없이 recoil만으로 가능함 - 내부적으로 캐싱이 됨
: 동일한 atom 값에 대해 내부적으로 메모이즈된 값을 반환하여 속도가 빠름
* 단어 정리
boilerplate : 변형이 거의 없는 여러 장소에서 반복되는 코드의 섹션(‘별 수정 없이 반복적으로 사용되는 코드’를 자동으로 생성해주는 것)
2. Recoil의 진행 순서
: 기존 리액트 철학인 탑→다운
에서 작은 상태들을 쌓아 바텀→업
스타일로 상태관리 철학을 변경함
- 바닥부터 조합
- 아톰을 조합해 더 큰 상태를 만듦
- 비동기 상태도 조합이 가능함
3. Recoil의 장점
- react와 업데이트 방향이 같음
- 내부적으로 자동적으로 캐싱되어 빠름(side-effect 존재)
- 상태를 분산적으로 두어 코드 스플리팅이 가능
4. Recoil의 단점
안정성
- UNSTABLE한 API
- 2022.07 현재 최신 버전이 0.7.4
- 저장소명이 facebookexperimental/Recoil
개발자 도구의 부재
- useRecoilSnapshot()가 존재하지만 UNSTABLE
부족한 레퍼런스
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
- Lodable 객체
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의 흐름을 벗어나지 않고 거의 동일하게 흘러감
- Component Mounts
- Fetch Data
- 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도 가능함
- key : 내부적으로 atom을 식별하는 데 사용되는 고유한 문자열
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 사용법