DEV Community

Hash
Hash

Posted on • Edited on

What is React Context? + Pro Tips

React Context is a built-in feature that lets you share data across your component tree without manually passing props down through every level. Think of it as a way to create a "global" state for a specific part of your app. It's perfect for data that many components need, like user authentication, theme settings, or language preferences.

Why Use Context?

  • Avoid Props Drilling: No more passing props through intermediate components that don't need them.
  • Cleaner Code: Reduces clutter and makes your component tree easier to read.
  • Centralized State: Manage shared data in one place, making it easier to update and maintain.

When to Use Context (and When Not To)

Good Use Cases:

  • Theme Switching: Dark mode, light mode, or custom themes.
  • User Authentication: Sharing user data across components.
  • Language/Localization: Managing translations and locale settings.
  • Global State Management: For simpler apps, Context can replace Redux or MobX.

When to Skip Context:

  • Small, Local State: If you only need to pass props a few levels down, stick with props.
  • Frequent Updates: Context can cause unnecessary re-renders if not optimized. For high-frequency updates, consider alternatives like Redux or Zustand.
  • Component Reusability: Overusing Context can make components harder to reuse. If you only need to avoid passing a few props, try component composition instead.

How to Use Context: A Quick Guide

1. Create a Context

// ThemeContext.js
import React, { createContext, useState } from 'react';

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
Enter fullscreen mode Exit fullscreen mode

2. Wrap Your App (or Part of It) with the Provider

// App.js
import { ThemeProvider } from './ThemeContext';

function App() {
  return (
    <ThemeProvider>
      <YourApp />
    </ThemeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. Consume the Context

// ThemedButton.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button
      onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
      style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#333' : '#fff' }}
    >
      Toggle Theme
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Top-Notch Tips for Using Context

1. Split Contexts for Better Performance

Instead of putting everything in one Context, split it into smaller contexts. This way, only components that need specific data will re-render.

// UserContext.js
export const UserContext = createContext();

// ThemeContext.js
export const ThemeContext = createContext();
Enter fullscreen mode Exit fullscreen mode

2. Use useMemo and useCallback to Prevent Unnecessary Re-renders

If your Context value changes frequently, wrap it in useMemo to avoid re-renders:

const value = useMemo(() => ({ theme, setTheme }), [theme]);
Enter fullscreen mode Exit fullscreen mode

3. Combine Context with Custom Hooks

Create custom hooks to encapsulate Context logic and make it easier to use:

// useTheme.js
export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
};
Enter fullscreen mode Exit fullscreen mode

4. Avoid Nested Providers

Too many nested providers can make your code hard to read. Consider using a single provider with multiple contexts:

function AppProvider({ children }) {
  return (
    <ThemeProvider>
      <UserProvider>
        {children}
      </UserProvider>
    </ThemeProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

5. Test Your Context

Use React Testing Library to ensure your Context works as expected:

import { render, screen } from '@testing-library/react';
import { ThemeProvider } from './ThemeContext';

test('renders themed button', () => {
  render(
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
  expect(screen.getByText('Toggle Theme')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls and How to Avoid Them

  • Re-renders: If your Context value changes, all consuming components will re-render. Use useMemo and useCallback to optimize.
  • Missing Provider: Always wrap your app (or the part that needs Context) with a Provider. Otherwise, useContext will return undefined.
  • Overuse: Don't use Context for everything. If you only need to pass props a few levels down, stick with props or component composition.

Final Thoughts

React Context is a powerful tool for sharing data across your component tree. Use it wisely, and it can simplify your code and improve maintainability. For more advanced state management, consider libraries like Redux or Zustand.

Happy coding!


References:

Top comments (0)