Component State vs Global State
Understanding when to use local component state versus global application state is crucial for React development. Local state is perfect for component-specific data that doesn't need to be shared, while global state should be used for data that multiple components need to access. This decision impacts performance, maintainability, and code organization. Making the wrong choice can lead to prop drilling hell or unnecessary re-renders across your application. The key is to start with local state and only elevate to global state when you find yourself passing props through multiple layers or when the same data is needed in distant parts of your component tree.
Core Principles
- ▸Start with local state by default - it's simpler and more performant
- ▸Elevate to global state only when multiple components need the same data
- ▸Consider component composition before reaching for global state
- ▸Use Context API for cross-cutting concerns like themes and authentication
- ▸Choose specialized solutions for server state (React Query, SWR)
Local State Example
1// Local Component State - Perfect for UI-specific state2import React, { useState } from 'react';34const SearchComponent = () => {5 // Local state for search input6 const [searchTerm, setSearchTerm] = useState('');7 const [isSearching, setIsSearching] = useState(false);8 const [suggestions, setSuggestions] = useState([]);910 // Local state for UI toggles11 const [showFilters, setShowFilters] = useState(false);12 const [selectedFilters, setSelectedFilters] = useState([]);1314 const handleSearch = async () => {15 setIsSearching(true);16 try {17 const results = await searchAPI(searchTerm, selectedFilters);18 setSuggestions(results);19 } finally {20 setIsSearching(false);21 }22 };2324 return (25 <div>26 <input27 value={searchTerm}28 onChange={(e) => setSearchTerm(e.target.value)}29 placeholder="Search..."30 />3132 <button onClick={() => setShowFilters(!showFilters)}>33 {showFilters ? 'Hide' : 'Show'} Filters34 </button>3536 {showFilters && (37 <FilterPanel38 selected={selectedFilters}39 onChange={setSelectedFilters}40 />41 )}4243 <button onClick={handleSearch} disabled={isSearching}>44 {isSearching ? 'Searching...' : 'Search'}45 </button>4647 {suggestions.map(item => (48 <div key={item.id}>{item.name}</div>49 ))}50 </div>51 );52};
Global State Example
1// Global State - For data shared across components2import { create } from 'zustand';3import { persist } from 'zustand/middleware';45// User authentication state - needed everywhere6const useAuthStore = create(7 persist(8 (set, get) => ({9 user: null,10 token: null,11 isAuthenticated: false,1213 login: async (credentials) => {14 const response = await authAPI.login(credentials);15 set({16 user: response.user,17 token: response.token,18 isAuthenticated: true19 });20 },2122 logout: () => {23 set({ user: null, token: null, isAuthenticated: false });24 authAPI.logout();25 },2627 updateProfile: (updates) => {28 set({ user: { ...get().user, ...updates } });29 }30 }),31 {32 name: 'auth-storage'33 }34 )35);3637// Shopping cart state - accessed from multiple pages38const useCartStore = create((set, get) => ({39 items: [],40 totalAmount: 0,4142 addItem: (product) => {43 const items = get().items;44 const existingItem = items.find(item => item.id === product.id);4546 if (existingItem) {47 set({48 items: items.map(item =>49 item.id === product.id50 ? { ...item, quantity: item.quantity + 1 }51 : item52 )53 });54 } else {55 set({ items: [...items, { ...product, quantity: 1 }] });56 }5758 get().calculateTotal();59 },6061 removeItem: (productId) => {62 set({ items: get().items.filter(item => item.id !== productId) });63 get().calculateTotal();64 },6566 calculateTotal: () => {67 const total = get().items.reduce(68 (sum, item) => sum + item.price * item.quantity,69 070 );71 set({ totalAmount: total });72 }73}));7475// Usage in components76const Header = () => {77 const { user, logout } = useAuthStore();78 const { items } = useCartStore();7980 return (81 <header>82 <div>Welcome, {user?.name}</div>83 <div>Cart ({items.length})</div>84 <button onClick={logout}>Logout</button>85 </header>86 );87};
Best Practices
- ✓Use local state for UI-specific concerns (form inputs, toggles, loading states)
- ✓Use global state for data shared across multiple components
- ✓Keep global state minimal and focused
- ✓Consider component composition before reaching for global state
- ✓Use React Context for prop drilling issues, not complex state