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
- Dependency Graph - Visualize context flow
- useWhyDidYouUpdate - Debug context re-renders
- Performance - Optimize context usage