Skip to main content

Recoil Adapter

Integrate React Dev Debugger with Recoil for comprehensive atom and selector tracking.

Installation

npm install react-dev-debugger recoil

Basic Setup

atoms.ts
import { atom } from 'recoil';
import { createRecoilAdapter } from 'react-dev-debugger/adapters/recoil';

// Define your atoms
export const countState = atom({
key: 'countState',
default: 0,
});

export const userState = atom({
key: 'userState',
default: null,
});

// Connect debugger
createRecoilAdapter({
atoms: [
{ atom: countState, name: 'count' },
{ atom: userState, name: 'user' },
],
});

Live Playground

Counter State

Count: 0

Name State

Length: 9

Todos State

    Total: 0Completed: 0Pending: 0

    Atom States

    Recoil Adapter Configuration

    import { atom, selector } from 'recoil';
    import { createRecoilAdapter } from 'react-dev-debugger/adapters/recoil';
    
    // Create atoms
    const counterState = atom({
      key: 'counterState',
      default: 0,
    });
    
    const todosState = atom({
      key: 'todosState',
      default: [],
    });
    
    // Create selector
    const todoStatsSelector = selector({
      key: 'todoStatsSelector',
      get: ({ get }) => {
        const todos = get(todosState);
        return {
          total: todos.length,
          completed: todos.filter(t => t.completed).length,
        };
      },
    });
    
    // Create adapter
    const adapter = createRecoilAdapter({
      name: 'My Store',
      atoms: [counterState, todosState],
      selectors: [todoStatsSelector],
    });
    
    // Subscribe to changes
    adapter.subscribe((state) => {
      console.log('Atom states:', state.atoms);
    });

    Usage in Components

    Counter.tsx
    import { useRecoilState } from 'recoil';
    import { countState } from './atoms';

    export function Counter() {
    const [count, setCount] = useRecoilState(countState);

    return (
    <div>
    <h2>Count: {count}</h2>
    <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
    );
    }

    Selectors

    Track derived state with Recoil selectors:

    atoms.ts
    import { atom, selector } from 'recoil';
    import { createRecoilAdapter } from 'react-dev-debugger/adapters/recoil';

    export const todoListState = atom({
    key: 'todoListState',
    default: [],
    });

    export const todoListStatsState = selector({
    key: 'todoListStatsState',
    get: ({ get }) => {
    const todoList = get(todoListState);
    const totalNum = todoList.length;
    const totalCompletedNum = todoList.filter((item) => item.isComplete).length;
    const totalUncompletedNum = totalNum - totalCompletedNum;

    return {
    totalNum,
    totalCompletedNum,
    totalUncompletedNum,
    };
    },
    });

    createRecoilAdapter({
    atoms: [
    { atom: todoListState, name: 'todoList' },
    { atom: todoListStatsState, name: 'todoStats' },
    ],
    });

    Atom Families

    Track dynamic atoms with atom families:

    atoms.ts
    import { atomFamily } from 'recoil';
    import { createRecoilAdapter } from 'react-dev-debugger/adapters/recoil';

    export const itemState = atomFamily({
    key: 'itemState',
    default: (id) => ({ id, name: '', completed: false }),
    });

    // Track specific instances
    createRecoilAdapter({
    atomFamilies: [
    { family: itemState, name: 'items' },
    ],
    });

    Complete Example

    TodoApp.tsx
    import { useState } from 'react';
    import {
    RecoilRoot,
    useRecoilState,
    useRecoilValue,
    useSetRecoilState,
    } from 'recoil';
    import { todoListState, todoListStatsState } from './atoms';

    function TodoList() {
    const [todoList, setTodoList] = useRecoilState(todoListState);
    const [inputValue, setInputValue] = useState('');
    const stats = useRecoilValue(todoListStatsState);

    const addItem = () => {
    if (inputValue.trim()) {
    setTodoList([
    ...todoList,
    {
    id: Date.now(),
    text: inputValue,
    isComplete: false,
    },
    ]);
    setInputValue('');
    }
    };

    const toggleItem = (id) => {
    setTodoList(
    todoList.map((item) =>
    item.id === id ? { ...item, isComplete: !item.isComplete } : item
    )
    );
    };

    return (
    <div>
    <h1>Recoil Todo List</h1>

    <div>
    <input
    value={inputValue}
    onChange={(e) => setInputValue(e.target.value)}
    onKeyPress={(e) => e.key === 'Enter' && addItem()}
    />
    <button onClick={addItem}>Add</button>
    </div>

    <ul>
    {todoList.map((todo) => (
    <li key={todo.id}>
    <input
    type="checkbox"
    checked={todo.isComplete}
    onChange={() => toggleItem(todo.id)}
    />
    <span style={{
    textDecoration: todo.isComplete ? 'line-through' : 'none'
    }}>
    {todo.text}
    </span>
    </li>
    ))}
    </ul>

    <div>
    Total: {stats.totalNum} | Completed: {stats.totalCompletedNum} |
    Active: {stats.totalUncompletedNum}
    </div>
    </div>
    );
    }

    export default function App() {
    return (
    <RecoilRoot>
    <TodoList />
    </RecoilRoot>
    );
    }

    Async Selectors

    Track asynchronous data fetching:

    atoms.ts
    import { atom, selector } from 'recoil';

    export const userIDState = atom({
    key: 'userID',
    default: 1,
    });

    export const userDataState = selector({
    key: 'userData',
    get: async ({ get }) => {
    const userId = get(userIDState);
    const response = await fetch(`/api/user/${userId}`);
    return response.json();
    },
    });

    Configuration Options

    interface RecoilAdapterOptions {
    // Display name in debugger
    name?: string;

    // Track specific atoms
    atoms?: Array<{ atom: RecoilState; name: string }>;

    // Track atom families
    atomFamilies?: Array<{ family: any; name: string }>;

    // Maximum snapshots
    maxSnapshots?: number;
    }

    Debugging Tips

    View Atom Dependencies

    The dependency graph shows which selectors depend on which atoms.

    Async State

    Suspense boundaries and loading states are tracked in the timeline.

    Time-Travel

    Step through atom value changes to debug state transitions.

    Next Steps