JotaiJotai

상태
React를 위한 기본적이고 유연한 상태 관리

Devtools

설치

jotai-devtools를 프로젝트에 설치하여 시작하세요.

npm install jotai-devtools

참고 사항

  • <DevTools/>는 프로덕션 빌드에서 트리 쉐이킹이 가능하도록 최적화되어 있으며, 비프로덕션 환경에서만 작동합니다.
  • 훅(Hooks)은 개발 전용이며, 비프로덕션 환경에서 작동하도록 설계되었습니다.
  • 피드백은 환영합니다. Jotai DevTools GitHub 저장소에 이슈를 등록하거나 질문을 남겨주세요.

빠른 링크

UI DevTools

Jotai DevTool의 UI 기반 기능으로 개발 경험을 향상시켜 보세요.

Babel 플러그인 설정 - (선택 사항이지만 강력히 권장)

최적의 디버깅 경험을 위해 Jotai Babel 플러그인을 사용하세요. 자세한 가이드는 babel 페이지와 swc 페이지에서 확인할 수 있습니다.

예제:

{
"presets": [
// 이 프리셋은 두 가지 플러그인을 포함합니다:
// - jotai/babel/plugin-react-refresh: atom에 대한 핫 리로드를 활성화
// - jotai/babel/plugin-debug-label: atom에 디버그 라벨을 자동으로 추가
'jotai/babel/preset'
]
}

Vite + React 프로젝트 예제:

// vite.config.ts
export default defineConfig({
plugins: [
react({
babel: {
presets: ['jotai/babel/preset'],
},
}),
],
})

Next JS 설정

Next.js를 사용하지 않는다면 이 섹션을 건너뛰어도 됩니다.

UI CSS와 컴포넌트가 올바르게 트랜스파일되도록 transpilePackages를 활성화하세요.

// next.config.ts
const nextConfig = {
// 자세한 내용은 여기서 확인하세요 - https://nextjs.org/docs/advanced-features/compiler#module-transpilation
// UI CSS가 올바르게 트랜스파일되려면 아래 설정이 필요합니다 👇
transpilePackages: ['jotai-devtools'],
}
module.exports = nextConfig

사용 가능한 props

type DevToolsProps = {
// 기본값은 false
isInitialOpen?: boolean
// 커스텀 스토어 전달
store?: Store
// 기본값은 light
theme?: 'dark' | 'light'
// 트리거 버튼의 위치 설정
// 기본값은 `bottom-left`
position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
// CSP를 통해 jotai-devtools의 인라인 스타일을 허용하기 위한 커스텀 nonce
nonce?: string
options?: {
// 프라이빗 아톰은 `atomWithStorage`나 `atomWithLocation` 같은 아톰 생성자에서
// 내부 상태를 관리하기 위해 사용됩니다.
// 기본값은 `false`
shouldShowPrivateAtoms?: boolean
// Atom Viewer 탭, Timeline 탭 등에서 초기 렌더링 시 JSON 트리 뷰를 확장할지 여부
// 기본값은 `false`
shouldExpandJsonTreeViewInitially?: boolean
// 타임 트래블 재생 시 각 단계 간의 간격(밀리초 단위)
// 기본값은 `750ms`
timeTravelPlaybackInterval?: number
// 히스토리에 저장할 스냅샷의 최대 개수
// 숫자가 클수록 더 많은 메모리를 소비합니다.
// 기본값은 `Infinity`. 권장값: `~30`
snapshotHistoryLimit?: number
}
}

Usage

Provider-less

import { DevTools } from 'jotai-devtools'
import 'jotai-devtools/styles.css'
const App = () => {
return (
<>
<DevTools />
{/* 여러분의 앱 */}
</>
)
}

With Provider

import { createStore } from 'jotai'
import { DevTools } from 'jotai-devtools'
import 'jotai-devtools/styles.css'
const customStore = createStore()
const App = () => {
return (
<Provider store={customStore}>
<DevTools store={customStore} />
{/* 여러분의 앱 */}
</Provider>
)
}

미리보기

useAtomsDebugValue

useAtomsDebugValue는 React Devtools에서 모든 atom 값을 보여주는 React 훅입니다.

function useAtomsDebugValue(options?: {
store?: Store
enabled?: boolean
}): void

내부적으로는 DEV 모드에서만 효과가 있는 useDebugValue를 사용합니다. 이 훅은 훅이 위치한 곳에서 접근 가능한 모든 atom을 잡아냅니다.

예제

import { Provider } from 'jotai'
import { useAtomsSnapshot, useGotoAtomsSnapshot } from 'jotai-devtools/utils'
const petAtom = atom('cat')
const colorAtom = atom('blue')
const UpdateSnapshot = () => {
const snapshot = useAtomsSnapshot()
const goToSnapshot = useGotoAtomsSnapshot()
return (
<button
onClick={() => {
const newSnapshot = new Map(snapshot)
newSnapshot.set(petAtom, 'dog')
newSnapshot.set(colorAtom, 'green')
goToSnapshot(newSnapshot)
}}
>
Go to snapshot
</button>
)
}

useAtomDevtools

useAtomDevtools는 특정 아톰(atom)을 위한 ReduxDevTools 확장을 관리하는 React 훅입니다.

function useAtomDevtools<Value>(
anAtom: WritableAtom<Value, Value>,
options?: {
store?: Store
name?: string
enabled?: boolean
},
): void

useAtomDevtools 훅은 제네릭 타입 매개변수를 받습니다. 이 타입은 아톰에 저장된 타입을 반영합니다. 또한, 훅은 anAtomname 두 가지 호출 매개변수를 받습니다.
anAtom은 devtools 인스턴스에 연결될 아톰입니다. name은 devtools 인스턴스의 디버그 레이블을 정의하는 선택적 매개변수입니다. name이 정의되지 않은 경우, atom.debugLabel이 대신 사용됩니다.

Example_V5keMNSvJi2TtG5Coqt6Yj

import { useAtomDevtools } from 'jotai-devtools/utils'
// 아톰에 저장될 타입의 인터페이스
export interface Task {
label: string
complete: boolean
}
// 디버깅할 아톰
export const tasksAtom = atom<Task[]>([])
// useAtomDevtools의 name 파라미터가 undefined일 경우, 이 값이 대신 사용됨
tasksAtom.debugLabel = 'Tasks'
export const useTasksDevtools = () => {
// 디버깅할 아톰을 전달하여 간단히 훅을 호출할 수 있음
useAtomDevtools(tasksAtom)
// 커스텀 타입 파라미터를 지정
useAtomDevtools<Task[]>(tasksAtom)
// 같은 아톰에 두 개의 devtools 인스턴스를 부착하고 커스텀 이름으로 구분할 수 있음
useAtomDevtools(tasksAtom, 'Tasks (Instance 1)')
useAtomDevtools(tasksAtom, 'Tasks (Instance 2)')
}

useAtomsDevtools

⚠️ 주의: 이 훅은 실험적 기능입니다(피드백 환영). process.env.NODE_ENV !== 'production' 환경에서만 동작합니다.

useAtomsDevtools는 특정 하나의 아톰만 보여주는 useAtomDevtools와 달리, 스토어에 있는 모든 아톰을 보여주는 통합 버전입니다.

function useAtomsDevtools(
name: string,
options?: {
store?: Store
enabled?: boolean
},
): void

이 훅은 Redux devtools 인스턴스에 이름을 붙이기 위해 필요한 name 파라미터와 store 파라미터를 받습니다.

이 API의 제한 사항으로, useAtomsDevtools를 사용하는 컴포넌트는 소비하는 아톰들이 해당 컴포넌트보다 React 트리에서 더 아래에 위치해야 합니다(아래 예제의 AtomsDevtools 참조). AtomsDevtools 컴포넌트는 우리 앱에서 권장하는 모범 사례입니다.

Example_Z6jyt6JUpocHVStJFMKf9T

const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
...
}
const AtomsDevtools = ({ children }) => {
useAtomsDevtools('demo')
return children
}
export default function App() {
return (
<AtomsDevtools>
<Counter />
</AtomsDevtools>
)
}

useAtomsSnapshot

⚠️ 참고: 이 훅은 process.env.NODE_ENV !== 'production' 환경에서만 동작합니다. 프로덕션 환경에서는 정적인 빈 값을 반환합니다.

useAtomsSnapshot은 현재 마운트된 아톰과 그 상태의 스냅샷을 찍습니다.

function useAtomsSnapshot(options?: { store?: Store }): AtomsSnapshot

이 훅은 store 매개변수를 받아들이고 AtomsSnapshot을 반환합니다. AtomsSnapshot은 기본적으로 Map<AnyAtom, unknown>입니다. Map API를 사용하여 아톰과 그 상태를 순회할 수 있습니다. 이 훅은 주로 디버깅과 개발 도구 사용 사례를 위해 만들어졌습니다.

이 훅을 사용할 때는 주의해야 합니다. 모든 상태 변경에 대해 컴포넌트가 리렌더링될 수 있기 때문입니다.

import { Provider } from 'jotai'
import { useAtomsSnapshot } from 'jotai-devtools/utils'
const RegisteredAtoms = () => {
const atoms = useAtomsSnapshot()
return (
<div>
<p>Atom 개수: {atoms.size}</p>
<div>
{Array.from(atoms).map(([atom, atomValue]) => (
<p key={`${atom}`}>{`${atom.debugLabel}: ${atomValue}`}</p>
))}
</div>
</div>
)
}
const App = () => (
<Provider>
<RegisteredAtoms />
</Provider>
)

useGotoAtomsSnapshot

⚠️ 주의: 이 훅은 process.env.NODE_ENV !== 'production' 환경에서만 동작합니다. 프로덕션 환경에서는 빈 함수처럼 작동합니다.

useGotoAtomsSnapshot은 현재 Jotai 상태를 전달된 스냅샷과 일치하도록 업데이트합니다.

function useGotoAtomsSnapshot(options?: {
store?: Store
}): (values: Iterable<readonly [AnyAtom, unknown]>) => void

이 훅은 콜백을 반환하며, 이 콜백은 useAtomsSnapshot 훅에서 가져온 snapshot을 받아 Jotai 상태를 업데이트합니다. store 매개변수를 받을 수 있습니다. 이 훅은 주로 디버깅과 개발 도구 사용 사례를 위해 만들어졌습니다.