Jotai(상태 관리 패턴)
기존 Laravel Blade Template 기반의 프론트를 Next.js로 리뉴얼하는 프로젝트를 진행하며,
사용된 React 전역 상태 관리 패턴 중 하나인 Jotai에 대해 포스팅으로 정리해보려 합니다. 이글에서는 어플리케이션 성능 관련으로 다둘것이며, 사용법은 다루지 않겠습니다.
Jotai 란??
우선 Jotai가 왜 만들어졌고, 어떤 컨셉으로 개발되었는지부터 살펴보겠습니다. Jotai는 일본어로 ‘상태’를 의미하며, Poimandres(react-spring를 만든)팀의 몇몇 개발자들의 공동 작업으로 개발되었습니다.
Jotai는 React Context를 사용할 때 발생하는 리렌더링 문제(구독한 모든 컴포넌트의 리랜더링)를 해결하고자 만들어졌습니다. 이를 통해 흔히 말하는 Provider 지옥과 같은 구조적 문제들을 간결하게 풀 수 있습니다.
또한 Jotai는 Recoil에서 영감을 받아 원자(atom) 모델 기반으로 설계되었으며, Recoil과 유사한 점도 찾아볼 수 있습니다. 개인적으로 매우 리액트스럽다고 생각한다.
상향식 접근 방식
Jotai는 상향식 접근 방식을 통해 전역 상태를 atom(원자) 단위로 관리합니다. 기존의 Context API처럼 상위 컴포넌트에서 Provider로 상태를 내려주는 하향식 구조가 아니라, 각 컴포넌트가 필요한 상태(atom)를 직접 구독하는 구조입니다. 즉 상태를 중앙에서 관리되는 것이 아니라 각 컴포넌트에서 독립적으로 관리하고, 컴포넌트에서 필요할 때마다 불러와 사용하는 구조입니다.
이러한 방식은 상태 관리가 보다 분산되고 유연하게 이루어질 수 있도록 도와줍니다.
Jotai는 같은 Poimandres 팀에서 개발한 Zustand와의 차이점을 문서에서 설명하고 있으며, 각자의 장단점을 이해하고 상황에 맞게 선택할 수 있도록 비교한 자료도 제공합니다.
렌더링 성능
상태는 react에 렌더링 즉 성능과 직접적으로 영향을 줍니다. 리액트 컴포넌트 함수는 반드시 멱등성을 반드시 가져야하고, 렌더링 단계에서 여러 번 호출될 수 있으며, 마운트 시에도 반복 호출될 수 있습니다. 따라서 렌더링을 반드시 최대한 가볍게 유지해야 합니다.
멱등성: 멱등성, 멱등하다라는 것은 같은 입력은 곧 같은 출력하는 것처럼 몇번을 실행하더라도 동일한 상태를 지녔을때, 이것을 멱등성을 가졌다, 멱등하다라고 표현합니다.
작게 쪼개진 컴포넌트
atom을 구독한 컴포넌트는 필요한 부분만 리렌더링되도록 작성해야 합니다. *React가 랜더링시에 비교해야 할 범위가 작을수록 렌더링 시간도 짧아집니다.
// 않좋은 예
const Profile = () => {
const [name] = useAtom(nameAtom)
const [age] = useAtom(ageAtom)
return (
<>
<div>{name}</div>
<div>{age}</div>
</>
)
}
// Jotai에서 권장하는 예
const NameComponent = () => {
const name = useAtomValue(nameAtom)
return <div>{name}</div>
}
const AgeComponent = () => {
const age = useAtomValue(ageAtom)
return <div>{age}</div>
}
const Profile = () => {
return (
<>
<NameComponent />
<AgeComponent />
</>
)
}
복잡한 연산
복잡한 계산은 React 라이프사이클 외부에서 실행되도록 작성해야합니다.
// 안좋은 예
const MyComponent = () => {
const data = useAtomValue(dataAtom);
const result = heavyComputation(data);
return <div>{result}</div>;
};
상태값을 가져와 연산 과정을 실행후 사용하는 안좋은 예시 코드입니다. 코드상 랜더링될때마다 연산 과정이 실행되어 성능 저하로 이어지는 코드
const dataAtom = atom([]);
const computedAtom = atom((get) => {
const data = get(rawDataAtom);
return heavyComputation(data);
});
const MyComponent = () => {
const [value] = useAtom(computedAtom);
return <div>{value}</div>;
};
연산 과정을 atom 내부에서 처리하여, 컴포넌트에서는 단순 결과값만 구독하는 코드로 Jotai에서 권장하는 방식입니다.
Jotai가 말하는 성능 시점의 핵심 정리
근본적인 애플리케이션의 성능 저하의 주요 원인은 필요하지 않거나, 너무 많은 컴포넌트가 리렌더링되는 것!
- 상태를 작게 쪼개서 관리하라!
설계 단계에서부터 상태를 작은 단위로 관리하면 변경이 발생한 부분만 리렌더링되어 불필요한 렌더링을 줄일 수 있습니다.
- 구독 범위를 좁혀라!
컴포넌트 단위로 구독 범위를 좁혀서 작고 가벼운 단위 컴포넌트를 리렌더링을 하도록 해야합니다.
느낀점
Jotai 문서를 정리 학습하며 Jotai가 성능적으로 지양해야 할 점들에 대해 명확히 이해할 수 있었습니다.
그 과정에서 “왜 Jotai가 등장했는가?”, “기존 상태 관리 도구의 어떤 부분을 보완하고자 했는가?”에 대한 이유도 자연스럽게 느껴졌습니다.
결국 Jotai는 단순히 “전역 상태 관리”를 넘어서서, React 애플리케이션을 설계하고 성능 최적화하는 기준을 함께 제시해주는 점을 체감할 수 있었습니다.