기존의 참여한 프로젝트에서 Redux보다 Recoil이 처음하기엔 쉽다!!해서 채택해서 사용한 적이 있는데 그 당시 개인 일정으로 Recoil을 깊게 이해하지 못하고 프로젝트를 마무리한 적이 있다. 그 후 개인 프로젝트에서는 React Context API를 사용했다. 그래서 기존 개인프로젝트에서 백엔드 개발자 친구와 함께 협업하여 파이어베이스와 미흡한 부분을 변경 및 개선하는 단계를 가지며 협업 능력과 미흡한 기술을 스킬업하는 과정을 가지는 것을 목표로 잡았다.
그래서 이 포스트는 처음으로 React Context API 대신 Recoil을 적용하는 과정을 담아낼 계획이다.
상태 관리는 주로 Recoil와 Redux를 많이들 사용하고 그외 zstand와 같은 여러 기술들도 많다.
그 중에 대규모 상태를 관리해야하는 프로젝트에는 Redux가 더 적합합니다. 그러나 프로젝트가 대규모가 아닐경우, recoil은 컴포넌트 범위의 상태 관리를 강조하여 더 직관적이고 간단한 구조를 가졌기에 유리한 부분이 있어 선택하였고, 그리고 Context API는 리액트 내장 기능이며 간단한 전역 상태 관리에 적합하지만 Recoil은 보다 세밀한 상태 관리 기능을 제공하기 때문에 사용했습니다..
페이스북에서 개발한 자바스크립트 라이브러리로, 리액트 애플리케이션의 상태 관리를 위한 도구입니다.
리액트는 컴포넌트를 재사용하는 방식으로 개발하기 때문에 상태 관리가 복잡한데 Recoil은 이러한 단점을 보안한 상태 관리 방법을 제공합니다.
Recoil은 컴포넌트 범위의 상태를 지원하며 여러 특징을 가지고 있습니다.
상태 관리의 유연성
Recoil을 사용하여 상태를 개별적으로 관리가능하며 상태를 저장하고 조회하는 방법을 제공하고 상태를 변경하는 함수(effect)를 등록할 수 있습니다.
비동기 처리지원
Recoil은 데이터 가져오기 및 부작용과 같은 작업에 중요한 비동기 데이터 처리를 위한 기본 지원을 제공하여 애플리케이션 내에서 비동기 작업 처리를 단순화합니다.
React Hooks 통합
Recoil은 React Hooks 통합되어 있어 useRecoilState, useRecoilValue등의 훅을 사용하여 리액트 애플리케이션 내에서 사용이 편리합니다.
효율적인 재렌더링
Recoil은 세부적으로 종속성을 추적해 재렌더링을 최적화하고 구성 요소는 종속된 특정 상태가 변경될 때만 다시 렌더링 되어 성능과 사용자 경험을 향상시킵니다.
RecoilRoot는 Recoil 라이브러리를 사용하기 위해 리액트 애플리케이션 최상위 컴포넌트(App)에 한 번만 추가하여 사용하여 App 컴포넌트와 하위 컴포넌트에서 Recoil 기능을 사용합니다.
RecoilRoot는 initializeState() 함수와 override 속성을 선택적으로 사용할 수 있는데 initializeState 함수는 초기 상태 값을 설정할 수 있어 애플리케이션이 처음 실행될 때 한 번 호출되어 초기 상태 값을 제공해줍니다.
override 속성은 Recoil 속성은 테스트하거나 모의하기 위해 사용합니다. override를 사용하면 특정 리코일의 아톰의 초깃값을 변경할 수 있어 특정한 조건에서 Atom 혹은 Selector의 값을 임의적으로 변경하고 싶을 때 사용합니다.
아톰은 리덕스의 스토어와 같은 개념으로 Recoil의 상태 단위를 나타내며 변경과 구독이 가능합니다. 아톰은 여러 개로 생성이 가능하며 업데이트되면 구독하고 있는 컴포넌트는 새로운 값으로 업데이트되고 재렌더링 됩니다.
Atom 함수는 key와 default 속성을 가졌는데 key는 여러 아톰을 식별할 때 필요한 고유 문자열이고 default 속성은 아톰의 초깃값을 설정해줍니다.
(여러 아톰이 동일한 이름의 key를 가지면 오류가 발생하기 때문에 전역적으로 유일해야 합니다.)
const Atom = atom({
key: '키값',
default: 초기값,
});
셀렉터는 global state를 선언하는 함수 중 하나이며 아톰이 리코일에서 상태의 최소 단위라면 셀렉터는 아톰을 기반으로 파생된 데이터라고 합니다.
셀렉터는 side effect가 없는 순수 함수이기 때문에 같은 인풋이 들어오면 같은 인풋을 리턴해줍니다. 그래서 리코일의 상태를 셀렉터로 관리하면 기존의 값을 캐싱하기 때문에 불필요한 연산을 줄일 수 있습니다.
side effect란?
실행 도중 어떠한 객체를 접근해서 변화가 발생하는 행위이다.let arr // side effect 발생 X
let arr = "Hello, world" Arr1 = arr // arr 할당 1번, Arr1에 할당 1번 총 2번의 side effect 발생
셀렉터의 기능으로 2가지가 있습니다.
셀렉터 안에 선언된 아톰의 값이 변할 때, 아톰을 구독하고 있다가 셀렉터에 할당된 함수가 다시 한번 실행됩니다.
서버와 비동기 통신을 할 때 서버에서 받아온 값을 global state 값으로 사용하기 위해서 입니다.
npm install recoil
or yarn add recoil
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
{/* 나머지 애플리케이션 컴포넌트 */}
</RecoilRoot>
);
}
import { atom } from "recoil";
import { CartItem } from "@/interface/cart";
export const cartState = atom<CartItem[]>({
key: "cartState", // 고유한 key 값(원하는 이름 사용)
default: [], // 기본값
});
import { atom } from 'recoil';
import { recoilPersist } from "recoil-persist";
const { persistAtom } = recoilPersist();
export const exampleState = atom({
key: 'example',
default: [],
effects_UNSTABLE: [persistAtom],
});