일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 리액트오류
- 데이터베이스
- useEffect
- ChatGPT
- Polylang
- @Entity
- @Controller
- Login
- JPA
- router
- GET
- @Query
- 구글
- GA4
- 인텔리제이
- 워드프레스
- useContext
- 구글애널리틱스
- @Repository
- firebase
- ussstate
- Thymeleaf
- SEO
- 구글알고리즘
- 플러그인
- post
- linkedhastset
- HttpSession
- set
- db
- Today
- Total
개발천재
[ReactJS] 원자 단위로 상태 관리하기, Jotai 본문
Jotai란?
"Atom(원자)" 단위로 상태를 관리하는 React 상태 관리 라이브러리
Jotai는 React 애플리케이션에서 상태를 작고 독립적인 단위(atom)로 나누어 관리할 수 있게 해주는 가볍고 선언적인 상태 관리 라이브러리이다. 각 atom은 useState처럼 사용하면서도 전역으로 공유할 수 있고, 필요한 상태만 불러오거나 조합(파생 상태)할 수 있어 유연하고 테스트하기 쉬운 구조를 만들 수 있다. 비동기 상태도 기본적으로 지원하며, Recoil과 비슷한 방식이지만 훨씬 단순하고 가벼운 점이 특징이다.
Jotai를 사용해야할 때
상태를 작게 쪼개서 조립하고 싶을 때
예를 들어 버튼 클릭 수, 로그인 여부, 토글 상태 등 작고 독립적인 상태를 각각 atom으로 만들고, 필요한 컴포넌트에서만 사용할 수 있다. 이렇게 하면 필요할 때 조합해서 쓰면 되기 때문에 구조가 깔끔해진다.
// store.js
import { atom } from 'jotai'
export const countAtom = atom(0)
export const doubleCountAtom = atom((get) => get(countAtom) * 2)
// Counter.jsx
import { useAtom } from 'jotai'
import { countAtom, doubleCountAtom } from './store'
function Counter() {
const [count, setCount] = useAtom(countAtom)
const [double] = useAtom(doubleCountAtom)
return (
<div>
<p>Count: {count}</p>
<p>Double: {double}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
페이지 또는 컴포넌트별로 상태를 나누고 싶을 때
예를 들어 회원가입 페이지를 만든다고 했을 때 이름, 이메일, 비밀번호 각각 atom으로 관리할 수 있다. 상태가 atom으로 쪼개져 있어서 페이지를 이동해도 값이 유지된다.
아래의 예제를 보면 다단계 폼(step form)에서도 상태 유지하면서 페이지마다 필요한 것만 관리할 수 있다. 또한 이렇게 하면 컴포넌트 간 결합도 낮아지고 유지보수 편해진다.
// formAtoms.js
import { atom } from 'jotai'
export const nameAtom = atom('')
export const emailAtom = atom('')
export const passwordAtom = atom('')
// Step1.jsx
mport { useAtom } from 'jotai'
import { nameAtom } from './formAtoms'
function Step1() {
const [name, setName] = useAtom(nameAtom)
return (
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="이름" />
)
}
// Step2.jsx
import { useAtom } from 'jotai'
import { emailAtom } from './formAtoms'
function Step2() {
const [email, setEmail] = useAtom(emailAtom)
return (
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="이메일" />
)
}
비동기 데이터를 전역 상태처럼 관리하고 싶을 때
예를 들어 API로 유저 정보 가져온다고 했을 때 사용자 정보를 비동기로 받아와서 보여줄 수 있다.
Suspense와 연동도 가능해서 비동기 흐름도 깔끔하게 처리할 수 있다.
// userAtom.js
import { atom } from 'jotai'
export const userAtom = atom(async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users/1')
return await res.json()
})
// UserInfo.jsx
import { useAtom } from 'jotai'
import { userAtom } from './userAtom'
function UserInfo() {
const [user] = useAtom(userAtom)
return <div>{user.name} 님 반갑습니다!</div>
}
React Context가 복잡할 때 대체하고 싶을 때
Context로 상태를 공유하면 코드도 길어지고, 관리도 어려워진다. 이럴 땐 그냥 atom 하나 만들고, 어디서든 useAtom으로 꺼내 쓰면 상태를 공유할 수 있다.
아래의 예제는 다크모드 on/off를 전역 상태로 관리한 예제이다. 어떤 컴포넌트는 useAtom(darkModeAtom)만 쓰면 다크모드 상태를 공유할 수 있다.
// themeAtom.js
import { atom } from 'jotai'
export const darkModeAtom = atom(false)
// ToggleTheme.jsx
import { useAtom } from 'jotai'
import { darkModeAtom } from './themeAtom'
function ToggleTheme() {
const [darkMode, setDarkMode] = useAtom(darkModeAtom)
return (
<button onClick={() => setDarkMode(!darkMode)}>
{darkMode ? '라이트 모드' : '다크 모드'}
</button>
)
}
테스트나 상태 추적이 쉬운 구조를 원할 때
atom 단위로 상태가 쪼개져 있어서 유닛 테스트를 쉽게 할 수 있다. 또한 특정 상태만 따로 테스트하거나 mocking도 가능하다.
전체 앱 상태를 테스트하기보다, 작은 단위만 테스트할 때 사용하면 유용하다. 테스트 할 때는 debugModeAtom을 따로 Mock해서 테스트하기 쉽게 만들 수 있다.
// debugAtom.js
import { atom } from 'jotai'
export const debugModeAtom = atom(false)
// DebugPanel.jsx
import { useAtom } from 'jotai'
import { debugModeAtom } from './debugAtom'
function DebugPanel() {
const [debug, setDebug] = useAtom(debugModeAtom)
return (
<div>
<label>
<input
type="checkbox"
checked={debug}
onChange={(e) => setDebug(e.target.checked)}
/>
디버그 모드
</label>
</div>
)
}
Jotai 사용방법
Jotai 설치하기
터미널에 아래 코드를 입력하여 jotai를 설치한다.
npm install jotai
atom 만들기
import { atom } from 'jotai'
const countAtom = atom(0) // 기본값 0
atom 사용하기
import { useAtom } from 'jotai'
import { countAtom } from './store'
function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<div>
<button onClick={() => setCount((c) => c - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount((c) => c + 1)}>+</button>
</div>
)
}
'개발 준비 > ReactJS' 카테고리의 다른 글
[ReactJS] 상태 관리를 더 쉽게, Zustand (0) | 2025.04.30 |
---|---|
[ReactJS] 데이터 공유를 위한 useContext 알아보기 (0) | 2025.04.04 |
[ReactJS] Nested Route 중첩 라우팅 (0) | 2025.02.06 |
[ReactJS] 컴포넌트(Component) 이해하기, 만들기 (0) | 2025.02.06 |
[ReactJS] Props 이해하기, 사용하기 (0) | 2025.02.05 |