You built a React app with TypeScript and Tailwind CSS, and now you need to share state across components. Should you use the built-in React Context API or install a third-party library like Zustand?
- How React Context handles global state without extra dependencies
- Why Zustand uses an external store to prevent unnecessary component re-renders
- Code examples of both tools in a real TypeScript component
- Clear recommendations on when to use each approach
The case for React Context
React Context is built directly into React, meaning you do not need to install any extra packages. It works great for low-frequency updates like user themes, language preferences, or authenticated user sessions.
import { createContext, useContext, useState, ReactNode } from 'react';
interface ThemeContextType {
theme: 'light' | 'dark';
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const toggleTheme = () => setTheme(prev => prev === 'light' ? 'dark' : 'light');
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}This example sets up a basic theme switcher using standard React hooks and TypeScript interfaces.
The main downside is that any change to the context value forces every consuming component to re-render, which can slow down large apps.
The case for Zustand
Zustand is a tiny state management library that creates a centralized store outside of the React component tree. It lets components subscribe to only the exact slice of state they need, avoiding wasted re-renders.
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));This code defines a simple counter store with TypeScript types and an update action.
The key takeaway is that you can read and update this state anywhere in your app without wrapping your components in provider tree components.
Common mistakes
A common mistake with React Context is putting fast-changing data, like mouse coordinates or input fields, into a single global context object. This causes your entire app to lag because too many components re-render at once. Another mistake with Zustand is writing overly complex mega-stores instead of splitting your state into smaller, focused domain stores.
Conclusion
Use React Context for static or slow-changing values like themes and user auth. Install Zustand the moment your app needs to share frequent updates across distant components. Open your current project right now and move one messy prop-drilling state into Zustand to see how much cleaner your code becomes.