Use Case: Small-to-medium apps, simple state, rapid prototyping
3. Context API React State
Concept
API
Description
Best Practice
createContext
React.createContext()
Create context object for passing data through component tree
Use for infrequently changing data (theme, auth, locale)
Context Provider
<Context.Provider>
Wrap components to provide context value to descendants
Split contexts by update frequency to minimize re-renders
useContext Hook
useContext(Context)
Subscribe to context value in functional components
Combine with useMemo to prevent unnecessary calculations
Re-render Issue
Every consumer re-renders
All context consumers re-render when provider value changes
Use composition, memo, or external library for optimization
Prop Drilling Solution
Context + Custom Hook
Avoid passing props through multiple component layers
Create custom useAuth(), useTheme() hooks for clean API
Example: Optimized Context Pattern
// contexts/AuthContext.jsimport { createContext, useContext, useState, useMemo } from 'react';const AuthContext = createContext(null);export function AuthProvider({ children }) { const [user, setUser] = useState(null); const [token, setToken] = useState(null); // Memoize value to prevent re-renders when provider re-renders const value = useMemo(() => ({ user, token, login: (userData, authToken) => { setUser(userData); setToken(authToken); }, logout: () => { setUser(null); setToken(null); } }), [user, token]); return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;}// Custom hook with error handlingexport function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within AuthProvider'); } return context;}// Usagefunction App() { return ( <AuthProvider> <Dashboard /> </AuthProvider> );}function Dashboard() { const { user, logout } = useAuth(); return <button onClick={logout}>{user.name}</button>;}
Warning: Context API is not optimized for frequent updates. For
high-frequency state changes (form inputs, animations), use local state or specialized libraries like
Zustand/Jotai.
4. MobX Observable State Trees
Concept
Decorator/API
Description
Advantage
Observable State
makeObservable()
Automatically track state changes and trigger component re-renders
Minimal boilerplate, reactive programming model
Computed Values
computed
Derive values from observables, automatically cache and update
Performance optimization, declarative derived state
Actions
action
Modify observable state, batch updates for performance
Transactional updates, better debugging
Reactions
autorun, reaction
Side effects that run automatically when observables change
Automatic synchronization, no manual subscriptions
MobX-State-Tree
types.model()
Runtime type system with snapshots, patches, time-travel
Type safety, undo/redo, JSON serialization
Example: MobX Store with Computed Values
import { makeObservable, observable, computed, action } from 'mobx';import { observer } from 'mobx-react-lite';class TodoStore { todos = []; constructor() { makeObservable(this, { todos: observable, completedCount: computed, addTodo: action, toggleTodo: action }); } get completedCount() { // Automatically recomputed when todos change return this.todos.filter(todo => todo.completed).length; } addTodo(text) { this.todos.push({ id: Date.now(), text, completed: false }); } toggleTodo(id) { const todo = this.todos.find(t => t.id === id); if (todo) todo.completed = !todo.completed; }}const todoStore = new TodoStore();// Observer component - re-renders only when used observables changeconst TodoList = observer(() => { return ( <div> <p>Completed: {todoStore.completedCount}/{todoStore.todos.length}</p> {todoStore.todos.map(todo => ( <div key={todo.id} onClick={() => todoStore.toggleTodo(todo.id)}> {todo.text} </div> ))} </div> );});
MobX Philosophy: Anything that can be derived from application state should be derived
automatically. Focus on what to track, not how to track it.
5. SWR Recoil Data Fetching
Library
Core Hook
Key Feature
Use Case
SWR NEW
useSWR(key, fetcher)
Stale-While-Revalidate strategy, automatic revalidation on focus/network
Data fetching with smart caching, real-time updates
Recoil
atom(), selector()
Atomic state management with derived state, asynchronous queries
Complex state graphs, React-centric state management
SWR Mutations
useSWRMutation()
Trigger remote mutations with automatic cache updates
POST/PUT/DELETE with optimistic UI updates
Recoil Atoms
useRecoilState()
Independent state units, minimal re-renders, shared across components
Fine-grained state subscriptions, component isolation
Recoil Selectors
selector({ get })
Pure functions deriving state from atoms, async data fetching