← 상태 관리 비교로 돌아가기

⚛️ Recoil 예제

Facebook의 React 상태 관리 라이브러리

📦 패키지 설치 필요

npm install recoil

현재는 로컬 상태로 구현되어 있습니다. 패키지 설치 후 코드 주석을 해제하세요.

✨ Recoil의 핵심 특징

  • Atom 패턴: 독립적인 상태 단위로 세밀한 구독
  • Selector: 파생 상태와 비동기 쿼리 지원
  • React Concurrent 지원: Suspense와 완벽 통합
  • Atom Effects: 상태 동기화와 부수 효과 처리
  • Time Travel Debugging: 상태 히스토리 추적

📝 Todo App 데모

할 일이 없습니다

📊 통계 (Selector로 계산됨)

0
전체
0
진행 중
0
완료

💻 Atom 정의 (기본 상태)

import { atom } from 'recoil';

// Todo 리스트 상태
const todoListState = atom<Todo[]>({
  key: 'todoListState', // 유니크한 ID
  default: [], // 기본값
});

// 필터 상태
const todoListFilterState = atom<'all' | 'active' | 'completed'>({
  key: 'todoListFilterState',
  default: 'all',
});

// 컴포넌트에서 사용
function TodoList() {
  const [todos, setTodos] = useRecoilState(todoListState);
  
  const addTodo = (text: string) => {
    setTodos([...todos, { 
      id: Date.now(), 
      text, 
      completed: false 
    }]);
  };
  
  return <div>...</div>;
}

🔄 Selector (파생 상태)

import { selector } from 'recoil';

// 필터링된 Todo 리스트 (파생 상태)
const filteredTodoListState = selector({
  key: 'filteredTodoListState',
  get: ({ get }) => {
    const filter = get(todoListFilterState);
    const list = get(todoListState);

    switch (filter) {
      case 'completed':
        return list.filter((item) => item.completed);
      case 'active':
        return list.filter((item) => !item.completed);
      default:
        return list;
    }
  },
});

// 통계 (파생 상태)
const todoListStatsState = selector({
  key: 'todoListStatsState',
  get: ({ get }) => {
    const todoList = get(todoListState);
    const totalNum = todoList.length;
    const completedNum = todoList.filter((item) => item.completed).length;
    const activeNum = totalNum - completedNum;

    return { totalNum, completedNum, activeNum };
  },
});

// 컴포넌트에서 사용
function TodoStats() {
  const stats = useRecoilValue(todoListStatsState);
  
  return (
    <div>
      <div>전체: {stats.totalNum}</div>
      <div>완료: {stats.completedNum}</div>
      <div>진행 중: {stats.activeNum}</div>
    </div>
  );
}

🌐 비동기 Selector (API 호출)

import { selector, useRecoilValue } from 'recoil';

// 사용자 정보 비동기 조회
const userInfoQuery = selector({
  key: 'userInfoQuery',
  get: async ({ get }) => {
    const userId = get(currentUserIdState);
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
});

// Suspense와 함께 사용
function UserInfo() {
  const userInfo = useRecoilValue(userInfoQuery);
  
  return (
    <div>
      <h2>{userInfo.name}</h2>
      <p>{userInfo.email}</p>
    </div>
  );
}

function App() {
  return (
    <RecoilRoot>
      <Suspense fallback={<div>Loading...</div>}>
        <UserInfo />
      </Suspense>
    </RecoilRoot>
  );
}

✅ 장점

  • • Selector를 통한 파생 상태 자동 계산
  • • 비동기 처리 내장 (Suspense 지원)
  • • 세밀한 리렌더링 최적화
  • • React Concurrent Mode 완벽 지원
  • • Atom Effects로 부수 효과 관리
  • • Time Travel Debugging

⚠️ 단점

  • • 큰 번들 사이즈 (~21KB)
  • • RecoilRoot Provider 필요
  • • Key 관리 필요 (충돌 방지)
  • • 실험적인 API 일부 포함
  • • React에만 사용 가능