개발/프론트엔드

리코일을 도입해보십다

paice 2025. 3. 26. 01:19

회사에 입사한 지 두 달쯤 됐을 무렵, 우연한 기회로 사이드 프로젝트에 참여하게 됐다!

회사에서 TF로 진행 중인 개발도 재미있지만, 나만의 서비스를 만들어보는 건 또 다른 의미로 다가오는 것 같다.

 

이번 프로젝트는 Vite + 리액트 기반이라 개발 자체는 크게 어렵지 않은데,
나는 중간에 합류한 입장이라 기존 팀의 개발 방식과 툴에 맞춰보려고 한다.

상태 관리는 Recoil이라는 라이브러리를 쓰고 있어서, 아직 익숙하진 않지만 간단하게 개념부터 정리해보고 시작해보려 한다.


우선, 리코일은 뭘까?

1. 리코일의 개념

리코일은 페이스북에서 개발한 React 애플리케이션을 위한 상태 관리 라이브러리로, 공유 상태비동기 데이터 흐름을 쉽게 다룰 수 있도록 설계되었으며, 아래와 같은 특징을 갖는다.

 

1. Atoms – 상태의 최소 단위

  • Atom은 Recoil에서 상태를 정의하는 가장 기본적인 단위
  • useRecoilState() 훅을 통해 읽고 쓸 수 있음
  • 여러 컴포넌트에서 같은 Atom을 구독하면, 하나의 컴포넌트에서 Atom을 업데이트할 때 모든 구독 컴포넌트가 자동으로 최신 상태로 갱신됨
const textState = atom({
  key: 'textState', // 고유 키
  default: '',      // 초기값
});

 

2. Selectors – 파생 상태 (Derived State)

  • Selector는 하나 이상의 Atom 혹은 다른 Selector로부터 값을 계산하는 함수
  • 메모이제이션되어 있어 입력값이 동일하면 재계산하지 않음
  • 비동기 로직(async get)도 지원하여 서버 데이터 처리에도 유리함
const charCountState = selector({
  key: 'charCountState',
  get: ({ get }) => {
    const text = get(textState);
    return text.length;
  },
});

 

3. 동시성(Concurrency) & 비동기 흐름

  • React의 Concurrent Mode와 호환되며, Suspense를 활용한 비동기 데이터 로딩에 최적화되어 있음
  • Selector 내에서 Promise를 리턴하면 해당 값은 React Suspense에 의해 처리됨

4. 컴포넌트 기반 상태 구독

  • Recoil은 각 컴포넌트가 필요한 상태(Atom/Selector)만 구독하기 때문에, 불필요한 렌더링을 최소화할 수 있음
  • 이는 Recoil이 전역 상태를 지역적으로 다루게 해주며, 성능 최적화에 유리함

5. 간결하고 직관적인 API

  • useRecoilState, useRecoilValue, useSetRecoilState 같은 React 친화적 훅으로 상태를 쉽게 다룰 수 있음
  • 보일러플레이트가 적어 초기 도입이 간편함

이러한 특징 덕분에 Recoil은 복잡한 애플리케이션의 상태를 보다 효율적이고 직관적으로 관리할 수 있는 솔루션으로 사용된다고 한다.

나 역시 기존에는 Redux Toolkit을 주로 사용해왔기 때문에, 프론트엔드 개발자들이 많이 사용하는 Recoil, Redux Toolkit, 그리고 Zustand 세 가지 상태 관리 라이브러리를 비교해보고자 한다.


2. Recoil , Redux Toolkit, Zustand 비교

특징 Recoil Redux Toolkit Zustand
개념 Atom과 Selector를 기반으로 파생 상태 구성 Redux 패턴(Action, Reducer 등)을 간소화한 상태 관리 도구 간단한 훅 기반의 글로벌 상태 관리 (Flux 패턴 없음)
설치 및 설정 React 전용, 간결한 설정 미들웨어 포함한 최소 설정으로 바로 사용 가능 거의 설정 없이 훅으로 바로 상태 정의 및 사용 가능
학습 곡선 React 개발자에게 직관적, Suspense와 잘 통합됨 기존 Redux보다 쉬움,
다만 Redux 개념은 여전히 필요
매우 낮음.
상태 정의와 사용이 단순하고 직관적임
상태 업데이트 Atom 단위로 세밀한 상태 업데이트 가능 Immer 내장으로 상태 불변성 유지하면서 간편하게 업데이트 가능 원하는 필드만 부분적으로 업데이트, 컴포넌트 리렌더링 최소화
비동기 처리 Selector에서 비동기 처리 가능 (Suspense와 연동) createAsyncThunk 등 공식 지원 상태 내부에서 직접 비동기 처리 가능 (직관적 사용)
사용 대상 React 전용, 중대형 앱의 복잡한 상태 로직에 적합 대형 앱, 복잡한 상태 처리와 협업이 필요한 프로젝트에 적합 소형~중형 앱, 빠른 프로토타이핑이나 간단한 상태 관리에 최적

3. 리코일 활용 방법

리코일을 React 애플리케이션에 도입하는 기본적인 방법에 대해 간략히 정리해보겠다.

 

3.1. 설치

리코일은 npm 또는 yarn을 통해 쉽게 설치할 수 있다.

npm install recoil
# 또는
yarn add recoil

 

3.2. 기본 사용법

리코일을 사용하기 위해서는 최상위 컴포넌트를 RecoilRoot로 감싸야 한다.

이후, Atom과 Selector를 정의하고, 컴포넌트 내에서 해당 상태를 사용하는 방식으로 진행한다.

다음은 예제 코드이다.

import React from 'react';
import { atom, selector, useRecoilState, useRecoilValue, RecoilRoot } from 'recoil';

// 1. Atom: 상태의 기본 단위 정의
const counterState = atom({
  key: 'counterState', // 고유 키
  default: 0,         // 초기 값
});

// 2. Selector: 파생 상태 정의 (Atom을 기반으로 계산)
const doubleCounterState = selector({
  key: 'doubleCounterState',
  get: ({ get }) => {
    const count = get(counterState);
    return count * 2;
  },
});

function Counter() {
  // Atom을 읽고 수정할 수 있는 훅
  const [count, setCount] = useRecoilState(counterState);
  // Selector를 통해 파생된 값 읽기
  const doubleCount = useRecoilValue(doubleCounterState);

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <p>두 배 값: {doubleCount}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

function App() {
  return (
    <RecoilRoot>
      <Counter />
    </RecoilRoot>
  );
}

export default App;


4. 결론

리코일은 React 개발자에게 친숙한 API와 유연한 상태 관리를 제공함으로써,

복잡한 애플리케이션에서도 보다 직관적인 데이터 흐름을 구성할 수 있게 도와준다.
특히 Redux에 익숙하지 않거나, 더 간결한 방식의 상태 관리를 원한다면 Recoil은 좋은 선택이 될 수 있다는 생각이 들었다.