Skip to main content

useTrackedContext

Track Context API changes with automatic provider and consumer monitoring.

Overview

useTrackedContext and createTrackedProvider help you debug Context API by tracking when context values change and which components consume them.

API

// Create a tracked provider
const TrackedProvider = createTrackedProvider(YourContext, 'contextLabel');

// Use tracked context in components
const value = useTrackedContext(YourContext, 'contextLabel');

Basic Example

import { createContext } from 'react';
import { useTrackedContext, createTrackedProvider } from 'react-dev-debugger';

interface ThemeContext {
theme: 'light' | 'dark';
toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContext>({
theme: 'light',
toggleTheme: () => {},
});

// Create tracked provider
const TrackedThemeProvider = createTrackedProvider(ThemeContext, 'theme');

function App() {
const [theme, setTheme] = useState<'light' | 'dark'>('light');

const value = {
theme,
toggleTheme: () => setTheme(t => t === 'light' ? 'dark' : 'light'),
};

return (
<TrackedThemeProvider value={value}>
<YourApp />
</TrackedThemeProvider>
);
}

function ThemedButton() {
// Track context consumption
const { theme, toggleTheme } = useTrackedContext(ThemeContext, 'theme');

return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}

Live Playground

Context Provider

Theme Settings
const TrackedProvider = createTrackedProvider(
  ThemeContext, 
  'theme'
);

<TrackedProvider value={{ theme, language, notifications }}>
  <App />
</TrackedProvider>
Consumer Component
Theme: light
Language: en
Notifications: Enabled
function ThemedComponent() {
  const { theme, language } = useTrackedContext(
    ThemeContext, 
    'theme'
  );
  
  return <div>Theme: {theme}</div>;
}
Current Context Value
{ "theme": "light", "language": "en", "notifications": true }

Context Updates

No context updates yet

Advanced Examples

Multi-value Context

interface AppContext {
user: User | null;
settings: Settings;
notifications: Notification[];
}

const AppContext = createContext<AppContext>({
user: null,
settings: defaultSettings,
notifications: [],
});

const TrackedAppProvider = createTrackedProvider(AppContext, 'appContext');

function AppProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [settings, setSettings] = useState(defaultSettings);
const [notifications, setNotifications] = useState<Notification[]>([]);

const value = { user, settings, notifications };

return (
<TrackedAppProvider value={value}>
{children}
</TrackedAppProvider>
);
}

Auth Context

interface AuthContext {
isAuthenticated: boolean;
user: User | null;
login: (credentials: Credentials) => Promise<void>;
logout: () => void;
}

const AuthContext = createContext<AuthContext | undefined>(undefined);

const TrackedAuthProvider = createTrackedProvider(AuthContext, 'auth');

function useAuth() {
const context = useTrackedContext(AuthContext, 'auth');
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}

I18n Context

interface I18nContext {
language: string;
translations: Record<string, string>;
setLanguage: (lang: string) => void;
t: (key: string) => string;
}

const I18nContext = createContext<I18nContext>({
language: 'en',
translations: {},
setLanguage: () => {},
t: (key) => key,
});

const TrackedI18nProvider = createTrackedProvider(I18nContext, 'i18n');

function I18nProvider({ children }: { children: React.ReactNode }) {
const [language, setLanguage] = useState('en');
const [translations, setTranslations] = useState({});

const t = (key: string) => translations[key] || key;

const value = { language, translations, setLanguage, t };

return (
<TrackedI18nProvider value={value}>
{children}
</TrackedI18nProvider>
);
}

Debugging Features

Provider Updates

See when context values change:

  • Which properties changed
  • Old vs new values
  • Which provider triggered the update

Consumer Tracking

Identify which components consume context:

  • Component names
  • Which context properties they use
  • Re-render frequency

Dependency Graph

Visualize context flow:

  • Provider → Consumer relationships
  • Context propagation tree
  • Performance bottlenecks

Best Practices

✅ Do's

  • Use descriptive labels: 'authContext' instead of 'ctx'
  • Split large contexts: Multiple small contexts are easier to track
  • Memoize context values: Prevent unnecessary updates
  • Use custom hooks: Wrap context consumption in custom hooks

❌ Don'ts

  • Don't pass objects directly: Memoize to prevent re-renders
  • Don't put everything in one context: Split by domain
  • Don't forget dependencies: Include all used values

Performance Optimization

function OptimizedProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState(initialState);

// Memoize context value
const value = useMemo(() => ({
state,
updateState: setState,
}), [state]);

return (
<TrackedProvider value={value}>
{children}
</TrackedProvider>
);
}

TypeScript Support

Full type safety:

interface MyContext {
value: string;
setValue: (v: string) => void;
}

const MyContext = createContext<MyContext>({
value: '',
setValue: () => {},
});

// Type-safe provider
const TrackedProvider = createTrackedProvider(MyContext, 'myContext');

// Type-safe consumer
function MyComponent() {
const { value, setValue } = useTrackedContext(MyContext, 'myContext');
// value: string
// setValue: (v: string) => void
}

Next Steps