구미구미
디지털 노마드를 꿈꾸며
구미구미
전체 방문자
오늘
어제
  • 분류 전체보기 (28)
    • 알고리즘 (15)
      • 개념정리 (1)
      • 문제풀이 (13)
    • 웹 개발 (11)
      • HTML · CSS (0)
      • JS · TS (3)
      • React · Next.js (6)
      • Node.js (0)
    • TIL (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 자바스크립트
  • 개발
  • 코딩테스트
  • next.js
  • 백엔드
  • 웹개발 #자바스크립트 #타입스크립트 #JS #TS
  • 블록체인
  • 프론트엔드
  • nextjs
  • 이코테
  • 파이썬
  • 리액트
  • 백준
  • 프로그래머스
  • react
  • 알고리즘
  • javascript
  • 풀스택
  • typescript
  • I18N

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
구미구미

디지털 노마드를 꿈꾸며

[React] 전역상태관리 라이브러리 Recoil
웹 개발/React · Next.js

[React] 전역상태관리 라이브러리 Recoil

2023. 1. 30. 18:17

0. 도입 동기

최근 진행 중인 프로젝트에 전역상태관리가 필요하다고 판단하게 되어 Recoil을 도입하게 되었다.

이전에 Redux를 사용해본 적이 있었는데 Redux를 사용했을 때 규칙에 맞게 작성해야 하는 코드양이 많았던 것이 생각나서 이번 기회에 "React를 위한" 상태관리 라이브러리인 Recoil은 사용성이 어떨지 경험해보고 싶었다. 또한 Redux를 도입하게 되었을 때 Redux를 처음 접하는 팀원들의 러닝커브가 높아질 것에 대한 우려도 있었다.

 

 

1. Recoil이란

Recoil은 atom과 selector라는 두 가지 주요한 개념을 토대로 애플리케이션의 상태를 관리할 수 있게 해준다.

 

 

위 그림은 atoms(공유 상태)가 selectors(순수 함수)를 나타내는 화살표를 거쳐 컴포넌트로 내려가는 Recoil의 데이터 플로우를 그래프로 표현한 것이다. 각 컴포넌트들은 상태의 단위를 나타내는 atoms를 구독하게 되며 selectors는 atoms 상태값을 동기 또는 비동기 방식을 통해 변환하게 된다.

 

1.1. Atoms

- 상태의 단위- atom 업데이트 시 이를 구독하는 컴포넌트는 새로운 값을 반영하여 다시 렌더링 됨- 동일한 atom이 여러 컴포넌트에서 사용될 경우 모든 컴포넌트는 상태를 공유

- 모든 atom은 반드시 고유한 키를 가져야 함

- React 컴포넌트의 상태처럼 기본값(default)을 가질 수 있음

const ageState = atom({
  key: 'ageState',
  default: 24,
});

 

컴포넌트에서 atom 값을 읽고 쓰기 위해서는 훅을 사용한다. (이런 점이 Recoil이 Redux에 비해 React스러운 지점이 아닐까 싶다.)

useRecoilState라는 훅에 지정해준 키 값을 인자로 넣어 사용한다. 이렇게 하면 React의 useState를 쓰는 것과 거의 동일하게 상태를 사용할 수 있다.

 

atom의 상태는 사용되는 모든 컴포넌트에서 공유되기 때문에 한 컴포넌트에서 atom 값을 변경할 경우 다른 컴포넌트에서도 변경된 상태를 공유받을 수 있다.

 

function AgeButton() {
  const [age, setAge] = useRecoilState(ageState);
  return (
  	<button onClick={() => setAge((value) => value + 1)}>Add Age</button>
  )
}
function AgeTag() {
  const [age, setAge] = useRecoilState(ageState);
  return <p>I'm {age}</p>
}

AgeButton 버튼을 클릭할 경우 ageState atom을 사용하는 AgeTag에서의 텍스트가 함께 변경된다.

 

1.2. Selectors

-  atoms나 다른 selectors를 인자로 받는 순수 함수

- 상위의 atoms 또는 selectors가 업데이트 되면 하위의 selector 함수도 다시 실행됨

- 컴포넌트는 atoms를 구독하듯 selectors를 구독할 수 있음

- selectors 변경 시 컴포넌트는 다시 렌더링됨

❓ 순수 함수
- 부수 효과가 없는 함수
- 어떤 함수에 동일한 인자를 주었을 때 항상 같은 값을 리턴하며, 외부의 상태를 변경하지 않는 함수

 

Selectors는 상태를 기반으로 하는 파생 데이터를 계산하는 데 사용된다. 최소한의 상태는 atoms에 저장하고, 이로부터 파생되는 데이터는 selectors에 명시한 함수를 통해 계산함으로써 쓸모없는 상태의 보존을 방지할 수 있다.

 

실제로 이번 프로젝트의 한 컴포넌트에서 배율 정보를 나타내기 위해 두 가지 상태값을 사용하고 있었는데, 실제로 DB에 저장되는 값을 atom으로 지정하고, 이로부터 계산되어 사용되는 값을 selector 함수를 통해 계산하는 식으로 변경할 수 있었다.

 

function MyComponent() {
  const [size, setSize] = useState(1); // DB에 저장되는 실수값
  const [sizeInput, setSizeInput] = useState(100); // 실수값을 바탕으로 계산되는 퍼센티지 값
  ...
}

 

Recoil 도입 이전에는 위처럼 실제로 DB에 저장될 실수값을 나타내는 상태와 이 실수값을 바탕으로 퍼센티지로 변환되어 input에 보여질 값을 나타내는 상태 두 가지가 따로 관리되고 있었다.

 

const sizeState = atom({
  key: 'sizeState',
  default: 1,
});

const sizeInputState = selector({
  key: 'sizeInputState',
  get: ({ get }) => {
  	const size = get(sizeState);
    return size * 100;
  },
});
function MyComponent() {
  const [size, setSize] = useRecoilState(sizeState);
  const sizeInput = useRecoilValue(sizeInputState);
  ...
}

 

이를 위와 같이 atom과 selector로 분리해 필요한 최소 단위 상태인 size값만 관리를 하면서도 이로부터 파생되는 필요한 값을 적절히 계산하여 사용할 수 있었다. 또한 위처럼 atom이나 selector의 값을 읽어오기만 할 때는 useRecoilValue 훅을 사용할 수 있다.

 

또한 selector에 set 프로퍼티를 추가하여 selector를 writable한 상태로 만들 수도 있다.

const sizeState = atom({
  key: 'sizeState',
  default: 1,
});

const sizeInputState = selector({
  key: 'sizeInputState',
  get: ({ get }) => {
  	const size = get(sizeState);
    return size * 100;
  },
  set: ({ set }, sizeInput) => {
    set(sizeState, sizeInput / 100);
  }
});

위처럼 setter 함수를 추가하여 복수의 atom 값을 변경할 수 있다.

'웹 개발 > React · Next.js' 카테고리의 다른 글

[Next.js] 국제화(i18n) 자동화 시스템 구축하기  (0) 2023.04.30
[React] Web API를 활용한 영상 녹화 구현하기  (0) 2023.03.31
[번역] useMemo와 useCallback 제대로 알고 사용하기  (0) 2023.02.28
multer로 AWS S3에 파일 업로드하기  (0) 2022.10.30
[Next.js] "window is not defined" 에러 해결  (0) 2022.05.14
    '웹 개발/React · Next.js' 카테고리의 다른 글
    • [React] Web API를 활용한 영상 녹화 구현하기
    • [번역] useMemo와 useCallback 제대로 알고 사용하기
    • multer로 AWS S3에 파일 업로드하기
    • [Next.js] "window is not defined" 에러 해결
    구미구미
    구미구미

    티스토리툴바