Jotai Adapter
Debug your Jotai atoms with React Dev Debugger's powerful visualization tools.
Installation
npm install react-dev-debugger jotai
Basic Setup
atoms.ts
import { atom } from 'jotai';
import { createJotaiAdapter } from 'react-dev-debugger/adapters/jotai';
// Define your atoms
export const countAtom = atom(0);
export const nameAtom = atom('');
// Connect debugger
createJotaiAdapter({
atoms: [
{ atom: countAtom, name: 'count' },
{ atom: nameAtom, name: 'name' },
],
});
Live Playground
Loading...
Usage in Components
Counter.tsx
import { useAtom } from 'jotai';
import { countAtom } from './atoms';
export function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
Derived Atoms
Track derived atoms and their dependencies:
atoms.ts
import { atom } from 'jotai';
import { createJotaiAdapter } from 'react-dev-debugger/adapters/jotai';
// Base atoms
const todosAtom = atom<Todo[]>([]);
const filterAtom = atom<'all' | 'active' | 'completed'>('all');
// Derived atom
const filteredTodosAtom = atom((get) => {
const todos = get(todosAtom);
const filter = get(filterAtom);
if (filter === 'active') return todos.filter(t => !t.completed);
if (filter === 'completed') return todos.filter(t => t.completed);
return todos;
});
// Track all atoms
createJotaiAdapter({
atoms: [
{ atom: todosAtom, name: 'todos' },
{ atom: filterAtom, name: 'filter' },
{ atom: filteredTodosAtom, name: 'filteredTodos' },
],
});
Complete Example
atoms.ts
import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';
import { createJotaiAdapter } from 'react-dev-debugger/adapters/jotai';
// User state
export const userAtom = atomWithStorage('user', null);
// Theme
export const themeAtom = atomWithStorage('theme', 'light');
// Todos
export const todosAtom = atom<Todo[]>([]);
// Actions as atoms
export const addTodoAtom = atom(
null,
(get, set, text: string) => {
const todos = get(todosAtom);
set(todosAtom, [
...todos,
{ id: Date.now(), text, completed: false },
]);
}
);
export const toggleTodoAtom = atom(
null,
(get, set, id: number) => {
const todos = get(todosAtom);
set(
todosAtom,
todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}
);
// Derived state
export const statsAtom = atom((get) => {
const todos = get(todosAtom);
return {
total: todos.length,
completed: todos.filter(t => t.completed).length,
active: todos.filter(t => !t.completed).length,
};
});
// Connect debugger
createJotaiAdapter({
atoms: [
{ atom: userAtom, name: 'user' },
{ atom: themeAtom, name: 'theme' },
{ atom: todosAtom, name: 'todos' },
{ atom: statsAtom, name: 'todoStats' },
],
});
TodoApp.tsx
import { useAtom, useSetAtom, useAtomValue } from 'jotai';
import {
todosAtom,
addTodoAtom,
toggleTodoAtom,
statsAtom,
} from './atoms';
export function TodoApp() {
const [input, setInput] = useState('');
const todos = useAtomValue(todosAtom);
const addTodo = useSetAtom(addTodoAtom);
const toggleTodo = useSetAtom(toggleTodoAtom);
const stats = useAtomValue(statsAtom);
const handleAdd = () => {
if (input.trim()) {
addTodo(input);
setInput('');
}
};
return (
<div>
<h1>Jotai Todo List</h1>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleAdd()}
/>
<button onClick={handleAdd}>Add</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
{todo.text}
</li>
))}
</ul>
<div>
Total: {stats.total} | Active: {stats.active} | Completed: {stats.completed}
</div>
</div>
);
}
Debugging Tips
View Atom Dependencies
The dependency graph shows which atoms depend on others. Derived atoms display their source atoms.
Track Write-Only Atoms
Action atoms (write-only) also appear in the timeline, showing when they're called and what they modified.
Async Atoms
Suspense-enabled async atoms show loading states and resolved values in the debugger.