Skip to content

Time-Travel Debugging with DevTools ​

Quick guide to enable and use time-travel debugging with Nexus State DevTools.

Overview ​

Time-travel debugging allows you to:

  • Navigate through your application's state history
  • Revert to previous states
  • Inspect how state changed over time
  • Debug complex state interactions

Quick Setup ​

Step 1: Import Required Modules ​

typescript
import { atom, createStore } from '@nexus-state/core';
import { SimpleTimeTravel } from '@nexus-state/time-travel';
import { devTools } from '@nexus-state/devtools';

Step 2: Create Store and TimeTravel Instance ​

typescript
const store = createStore();

// Create SimpleTimeTravel instance
const timeTravel = new SimpleTimeTravel(store, {
  maxHistory: 50,      // Maximum number of states to keep
  autoCapture: true,   // Automatically capture state changes
});

Step 3: Apply DevTools Plugin ​

typescript
const devtoolsPlugin = devTools();
devtoolsPlugin.apply(store);
// DevTools will automatically find and use timeTravel from store

Step 4: Use in Your App ​

typescript
function App() {
  const [count, setCount] = useAtom(countAtom, store);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </div>
  );
}

How to Use Time-Travel ​

1. Open Redux DevTools Extension ​

  1. Install Redux DevTools (Chrome/Firefox)
  2. Open DevTools in your browser (F12 or Right-click → Inspect)
  3. Navigate to the "Nexus State" tab

2. Navigate Through History ​

In the DevTools interface:

  • Timeline: Click on any state in the timeline to jump to it
  • Jump to State: Use the slider or input to jump to a specific state
  • Undo/Redo: Use the buttons to navigate through recent states
  • State Inspector: View the complete state tree at any point

3. Advanced Usage ​

Manual Time Travel ​

typescript
// Jump to specific state by index
timeTravel.jumpTo(5);

// Check if undo is available
if (timeTravel.canUndo()) {
  timeTravel.undo();
}

// Check if redo is available
if (timeTravel.canRedo()) {
  timeTravel.redo();
}

// Get current history
const history = timeTravel.getHistory();
console.log(`History length: ${history.length}`);

// Clear history
timeTravel.clearHistory();

Custom Action Names ​

typescript
const countAtom = atom(0, 'counter');

// Actions will be named automatically: "counter SET"
store.set(countAtom, 5);

// Or use batch for grouped actions
store.startBatch('user-update');
store.set(firstNameAtom, 'Jane');
store.set(lastNameAtom, 'Smith');
store.endBatch('user-update');
// This creates one action: "user-update"

Enable Only in Development ​

typescript
const store = createStore();
const timeTravel = new SimpleTimeTravel(store);

if (process.env.NODE_ENV === 'development') {
  const devtoolsPlugin = devTools({
    name: 'My App',
    maxAge: 100,  // Keep more history in development
    trace: true,  // Capture stack traces
  });
  
  devtoolsPlugin.apply(store);
}

Example: Counter with Time-Travel ​

typescript
import React from 'react';
import { useAtom } from '@nexus-state/react';
import { atom, createStore } from '@nexus-state/core';
import { SimpleTimeTravel } from '@nexus-state/time-travel';
import { devTools } from '@nexus-state/devtools';

const countAtom = atom(0, 'counter');

const store = createStore();
const timeTravel = new SimpleTimeTravel(store, {
  maxHistory: 50,
  autoCapture: true,
});

const devtoolsPlugin = devTools();
devtoolsPlugin.apply(store);
devtoolsPlugin.setTimeTravel(timeTravel); // Optional, auto-detected

function Counter() {
  const [count, setCount] = useAtom(countAtom, store);
  
  const historyLength = timeTravel.getHistory().length;
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <p>History: {historyLength} states</p>
      
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
      <button onClick={() => setCount(c => c - 1)}>Decrement</button>
      
      <div style={{ marginTop: '20px' }}>
        <h3>Time-Travel Controls:</h3>
        <button onClick={() => timeTravel.undo()} disabled={!timeTravel.canUndo()}>
          Undo
        </button>
        <button onClick={() => timeTravel.redo()} disabled={!timeTravel.canRedo()}>
          Redo
        </button>
      </div>
    </div>
  );
}

Troubleshooting ​

Time-Travel Not Working ​

  1. Ensure SimpleTimeTravel is created with the store
  2. Check that DevTools plugin is applied after creating timeTravel
  3. Verify Redux DevTools extension is installed
  4. Check browser console for error messages

Performance Issues ​

  1. Reduce maxHistory option
  2. Disable autoCapture and manually call capture() only when needed
  3. Use state sanitization to reduce payload size
typescript
const timeTravel = new SimpleTimeTravel(store, {
  maxHistory: 20,        // Keep less history
  autoCapture: false,    // Manual capture
});

// Manually capture at key points
timeTravel.capture('user-login');

Missing States ​

If you don't see expected states in DevTools:

  1. Check that atoms are created after DevTools plugin is applied
  2. Verify atoms have names: atom(0, 'myAtom')
  3. Ensure autoCapture is true or manually call capture()

Best Practices ​

  1. Always name your atoms for better DevTools experience
  2. Use batch updates for related changes
  3. Enable time-travel only in development for production builds
  4. Sanitize sensitive data before sending to DevTools
typescript
const devtoolsPlugin = devTools({
  stateSanitizer: (state) => {
    const sanitized = { ...state };
    delete sanitized.token;
    delete sanitized.password;
    return sanitized;
  },
});