โš›๏ธ Context API Masterclass

Day 25-26: Complete Guide with Interactive Demos

๐Ÿ“š Context API Kya Hai?

Context API: A React feature that provides a way to pass data through the component tree without having to pass props down manually at every level. It's designed to share data that can be considered "global" for a tree of React components.

Simple shabdon mein: Imagine karo ek joint family hai. Agar dadi ko kuch batana hai pote ko, toh normal tarike se dadi โ†’ papa โ†’ beta โ†’ pota (prop drilling) karna padega. Lekin Context API ek loudspeaker ki tarah hai - dadi seedha announce kar deti hai aur pota sun leta hai! ๐Ÿ“ข

Problem ye solve karta hai: Prop drilling - jab aapko data 5-6 levels neeche bhejni ho toh har component mein props pass karna padta hai, chahe beech wale components ko us data ki zaroorat na ho.

๐ŸŽฏ Prop Drilling vs Context API

โŒ Prop Drilling

App (data)
Parent (props)
Child (props)
GrandChild (use)

Har level pe props pass karna padta hai

โ†’

โœ… Context API

Provider (data)
Parent
Child
Consumer (use)

Seedha access, beech wale ko tension nahi

1๏ธโƒฃ Context Create Karna & Provide Karna

Creating Context: The process of initializing a new context using React.createContext(), which returns a Context object with Provider and Consumer components.

Teen steps hain:

  1. Create: Context banao using createContext()
  2. Provide: Provider component se data wrap karo
  3. Consume: useContext hook se data access karo
// Step 1: Context Create karna import { createContext } from 'react'; const ThemeContext = createContext(); // Step 2: Provider Component banao function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); } // Step 3: useContext se consume karo function ThemedButton() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <button onClick={toggleTheme}> Current theme: {theme} </button> ); }

๐ŸŽฏ Live Demo: Theme Context

Neeche button click karke theme change karo - ye Context API use kar raha hai!

Current Theme: Light

Ye content theme ke according change hota hai. Context API se har component ko theme ka access mil jata hai bina props pass kiye!

Header Component
Sidebar Component
Footer Component

โ˜๏ธ Sabhi components ko same theme mil raha hai Context se

2๏ธโƒฃ useContext Hook - Deep Dive

useContext Hook: A React Hook that lets you read and subscribe to context from your component. It accepts a context object and returns the current context value for that context.

Kaise kaam karta hai? useContext ek subscription ki tarah hai. Jab bhi Provider mein value change hoti hai, sabhi consumers automatically re-render ho jate hain naye value ke saath. Ye real-time sync ki tarah hai!

๐Ÿ“ฅ Old Way (Consumer)

<ThemeContext.Consumer> {value => ( <div>{value}</div> )} </ThemeContext.Consumer>

Verbose aur nested

โœ… New Way (useContext)

const value = useContext(ThemeContext); return <div>{value}</div>

Clean aur simple

๐ŸŽฏ Live Demo: Multiple Contexts

Ek component multiple contexts use kar sakta hai!

User Context: Guest
Language Context: English
Theme Context: Light
// Multiple contexts ek saath use karna function MyComponent() { const { user } = useContext(UserContext); const { language } = useContext(LanguageContext); const { theme } = useContext(ThemeContext); return ( <div className={theme}> <h1>{language === 'hi' ? 'เคจเคฎเคธเฅเคคเฅ‡' : 'Hello'}, {user.name}!</h1> </div> ); }

3๏ธโƒฃ Re-render Issues & Optimization

Re-render Problem: When context value changes, all components consuming that context re-render, even if they only use a small part of the context value. This can cause performance issues in large applications.

Sabse badi problem: Jab Context ki value change hoti hai, toh SABHI components jo us context ko consume kar rahe hain, wo re-render ho jate hain - chahe unko us particular value ki zaroorat ho ya na ho! ๐Ÿ˜ฐ

Example: Agar aapke context mein user aur theme dono hain, aur sirf theme change hua, toh bhi wo components re-render honge jo sirf user use kar rahe hain!

๐ŸŽฏ Live Demo: Re-render Counter

Dekho kitni baar components re-render ho rahe hain!

Component A
Renders: 0
Uses: user.name
Component B
Renders: 0
Uses: user.age
Component C
Renders: 0
Uses: theme
โš ๏ธ Problem: Sabhi components re-render ho rahe hain, chahe unko us value ki zaroorat na ho!

โœ… Solutions for Re-render Issues

1. Split Contexts

Alag alag contexts banao different data ke liye

// โŒ Bad: Ek hi context <AppContext.Provider value={{ user, theme, settings }}> // โœ… Good: Alag contexts <UserContext.Provider> <ThemeContext.Provider> <SettingsContext.Provider>

2. useMemo for Value

Context value ko memoize karo

const value = useMemo( () => ({ user, theme }), [user, theme] ); <Context.Provider value={value}>

3. React.memo

Components ko memoize karo

const MyComponent = React.memo(function() { const { user } = useContext(UserContext); return <div>{user}</div> });

4. Context Selectors

Sirf required data select karo

// Custom hook banao const useUserName = () => { const { user } = useContext(UserContext); return user.name; };

4๏ธโƒฃ Context API vs Redux - Kab Kya Use Karein?

State Management Comparison: Context API is built into React for sharing data across components, while Redux is a separate library providing a more structured approach to state management with additional features like middleware, time-travel debugging, and strict unidirectional data flow.

Confusion clear karte hain: Context API aur Redux dono state management ke liye hain, lekin dono ka use case alag hai. Context API React ka built-in feature hai, Redux ek external library hai with more features.

Feature Context API Redux
Setup Complexity โœ“ Simple & Quick โœ— Complex Boilerplate
Bundle Size โœ“ 0 KB (Built-in) โœ— ~10 KB (External)
DevTools โœ— Limited โœ“ Excellent (Time-travel)
Middleware Support โœ— No โœ“ Yes (Thunk, Saga)
Performance โœ— Can cause re-renders โœ“ Optimized with selectors
Learning Curve โœ“ Easy โœ— Steep
Best For Small to medium apps, theme, auth Large apps, complex state logic

โœ… Use Context API When:

  • Small to medium sized app
  • Simple state sharing (theme, language, auth)
  • Don't want external dependencies
  • State doesn't change frequently
  • Quick prototyping
  • Learning React basics

โœ… Use Redux When:

  • Large scale application
  • Complex state logic & transformations
  • Need middleware (API calls, logging)
  • Time-travel debugging required
  • Multiple developers working
  • Strict state management patterns needed

Real advice: Agar aapka app chota hai aur sirf theme/auth manage karna hai, toh Context API perfect hai. Lekin agar aapka app bada hai, bahut saari API calls hain, complex state logic hai, toh Redux better choice hai. Don't over-engineer! ๐ŸŽฏ

5๏ธโƒฃ Global Theme Management with Context

Theme Management: A pattern where application-wide styling preferences (colors, fonts, spacing) are stored in context and consumed by all components, enabling features like dark mode, custom themes, and consistent UI across the application.

Real-world use case: Aajkal har app mein dark mode hota hai. Context API se aap ek jagah theme define karo aur puri app mein use karo. User preference save kar sakte ho localStorage mein!

๐ŸŽฏ Live Demo: Complete Theme System

Theme Showcase

Ye pura section theme ke according change ho raha hai!

Button
Card
Input

Current Theme: Light

// Complete Theme Context Implementation import { createContext, useState, useEffect } from 'react'; const themes = { light: { background: '#ffffff', text: '#333333', primary: '#667eea' }, dark: { background: '#1e1e1e', text: '#ffffff', primary: '#bb86fc' } }; export const ThemeContext = createContext(); export function ThemeProvider({ children }) { const [theme, setTheme] = useState( localStorage.getItem('theme') || 'light' ); // Save to localStorage whenever theme changes useEffect(() => { localStorage.setItem('theme', theme); document.body.className = theme; }, [theme]); const value = { theme, colors: themes[theme], setTheme }; return ( <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> ); } // Custom hook for easy access export const useTheme = () => { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within ThemeProvider'); } return context; };

6๏ธโƒฃ Authentication Management with Context

Auth Context: A pattern for managing user authentication state globally, including login status, user information, tokens, and authentication-related functions accessible throughout the application.

Sabse common use case: User login/logout ka state manage karna. Agar user logged in hai toh dashboard dikhao, nahi toh login page. Context se ye bahut easy ho jata hai - har component ko pata chal jata hai user logged in hai ya nahi!

๐ŸŽฏ Live Demo: Auth System

๐Ÿ”’ Please Login

Protected Components:
๐Ÿ”’ Login required to view
// Complete Auth Context Implementation import { createContext, useState, useEffect } from 'react'; export const AuthContext = createContext(); export function AuthProvider({ children }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); // Check if user is logged in on mount useEffect(() => { const token = localStorage.getItem('token'); if (token) { // Verify token and get user data fetchUserData(token); } else { setLoading(false); } }, []); const login = async (credentials) => { try { const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials) }); const { user, token } = await response.json(); localStorage.setItem('token', token); setUser(user); return { success: true }; } catch (error) { return { success: false, error }; } }; const logout = () => { localStorage.removeItem('token'); setUser(null); }; const value = { user, loading, login, logout, isAuthenticated: !!user }; return ( <AuthContext.Provider value={value}> {!loading && children} </AuthContext.Provider> ); } // Protected Route Component function ProtectedRoute({ children }) { const { isAuthenticated } = useContext(AuthContext); if (!isAuthenticated) { return <Navigate to="/login" />; } return children; }

7๏ธโƒฃ Context API Best Practices

1. โœ… Create Custom Hooks

Har context ke liye custom hook banao

export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error( 'useAuth must be used within AuthProvider' ); } return context; };

2. โœ… Split Large Contexts

Ek context mein sab kuch mat dalo

// โŒ Bad <AppContext value={{ user, theme, settings, cart, notifications }}> // โœ… Good <UserContext> <ThemeContext> <CartContext>

3. โœ… Memoize Context Value

Unnecessary re-renders se bacho

const value = useMemo( () => ({ user, login, logout }), [user] );

4. โœ… Provide Default Values

Context create karte waqt default value do

const ThemeContext = createContext({ theme: 'light', setTheme: () => {} });

5. โœ… Keep Context Close

Provider ko sirf wahan use karo jahan zaroorat ho

// โŒ Bad: Root level <App> <ModalContext> // โœ… Good: Specific section <Dashboard> <ModalContext>

6. โœ… Error Boundaries

Context errors ko handle karo

if (!context) { throw new Error( 'Component must be wrapped in Provider' ); }

โš ๏ธ Common Mistakes:

  • Har choti cheez ke liye context banana (overkill)
  • Context value ko directly object literal dena (har render pe naya object)
  • Bahut saare contexts nest karna (provider hell)
  • Context ko state management library samajhna (it's not Redux!)

๐ŸŽฏ Interview Questions (Basic to Advanced)

Click on each question to reveal the answer

Q1. Context API kya hai aur prop drilling problem kaise solve karta hai? (Basic) โ–ผ

Answer:

Context API: React ka built-in feature hai jo data ko component tree mein share karne ke liye use hota hai bina har level pe props pass kiye.

Prop Drilling Problem:

  • Jab data ko deeply nested components tak pass karna ho
  • Beech ke components ko data ki zaroorat nahi hoti but props pass karne padte hain
  • Code maintenance difficult ho jata hai

Context API Solution:

  • Provider component se data wrap karo
  • Koi bhi child component directly access kar sakta hai
  • Beech ke components ko touch nahi karna padta

Hinglish: Prop drilling matlab data ko 5-6 levels neeche bhejne ke liye har component mein props pass karna. Context API se seedha access mil jata hai, beech wale components ko tension nahi!

Q2. useContext hook kaise kaam karta hai? Consumer component se kya difference hai? (Basic) โ–ผ

Answer:

useContext Hook:

  • Modern way to consume context
  • Functional components mein use hota hai
  • Clean aur readable syntax
  • Multiple contexts easily use kar sakte ho
// useContext (Modern) const { user } = useContext(UserContext); // Consumer (Old way) <UserContext.Consumer> {({ user }) => <div>{user.name}</div>} </UserContext.Consumer>

Differences:

useContext Consumer
Hook (function) Component (JSX)
Clean syntax Nested/verbose
Easy to use multiple Nesting hell

Q3. Context value change hone pe unnecessary re-renders kaise avoid karein? (Intermediate) โ–ผ

Answer:

Problem: Jab context value change hoti hai, sabhi consuming components re-render hote hain, chahe unko us particular value ki zaroorat na ho.

Solutions:

1. Split Contexts:

// Alag contexts banao <UserContext.Provider> <ThemeContext.Provider> <App /> </ThemeContext.Provider> </UserContext.Provider>

2. useMemo for Context Value:

const value = useMemo( () => ({ user, updateUser }), [user] ); <Context.Provider value={value}>

3. React.memo for Components:

const MyComponent = React.memo(() => { const { user } = useContext(UserContext); return <div>{user.name}</div>; });

4. Context Selectors (Custom Hook):

const useUserName = () => { const { user } = useContext(UserContext); return user.name; };

Hinglish: Context ko chote chote parts mein todo, value ko memoize karo, aur components ko React.memo se wrap karo. Ye sab techniques combine karke unnecessary re-renders kam kar sakte ho!

Q4. Context API vs Redux - kab kya use karein? Real-world scenarios explain karo (Intermediate) โ–ผ

Answer:

Context API Use Cases:

  • Theme Management: Light/dark mode toggle
  • Authentication: User login state, basic user info
  • Language/i18n: Multi-language support
  • UI State: Modal open/close, sidebar toggle
  • Small Apps: Todo apps, personal projects

Redux Use Cases:

  • E-commerce: Cart, products, orders, complex state
  • Social Media: Posts, comments, likes, real-time updates
  • Dashboard: Multiple data sources, complex filters
  • Large Teams: Strict patterns, predictable state
  • Time-travel Debugging: Need to replay actions

Decision Tree:

โ“ State frequently change hoti hai? โ†’ Redux

โ“ Complex async logic hai? โ†’ Redux (with middleware)

โ“ Multiple developers? โ†’ Redux (better structure)

โ“ Simple state sharing? โ†’ Context API

โ“ Small app? โ†’ Context API

โ“ Don't want dependencies? โ†’ Context API

Real Example:

// E-commerce App Architecture // Context API for: - Theme (light/dark) - Auth (user login status) - Language (en/hi) // Redux for: - Products (list, filters, search) - Cart (add, remove, update quantity) - Orders (history, tracking) - Checkout (multi-step process)

Hinglish: Choti app hai aur sirf theme/auth chahiye? Context API perfect hai. Badi app hai, bahut saari API calls, complex logic? Redux use karo. Don't over-engineer - start simple!

Q5. Multiple nested Providers se "Provider Hell" kaise avoid karein? (Advanced) โ–ผ

Answer:

Problem - Provider Hell:

// โŒ Bahut nested, unreadable <AuthProvider> <ThemeProvider> <LanguageProvider> <NotificationProvider> <ModalProvider> <CartProvider> <App /> </CartProvider> </ModalProvider> </NotificationProvider> </LanguageProvider> </ThemeProvider> </AuthProvider>

Solution 1: Compose Providers (Best Practice)

// Create a composed provider function AppProviders({ children }) { return ( <AuthProvider> <ThemeProvider> <LanguageProvider> <NotificationProvider> {children} </NotificationProvider> </LanguageProvider> </ThemeProvider> </AuthProvider> ); } // Usage - Clean! <AppProviders> <App /> </AppProviders>

Solution 2: Compose Function (Advanced)

function composeProviders(...providers) { return ({ children }) => { return providers.reduceRight( (acc, Provider) => <Provider>{acc}</Provider>, children ); }; } // Usage const AllProviders = composeProviders( AuthProvider, ThemeProvider, LanguageProvider ); <AllProviders> <App /> </AllProviders>

Solution 3: Single Context with Multiple Values

// Combine related contexts const AppContext = createContext(); function AppProvider({ children }) { const auth = useAuthState(); const theme = useThemeState(); const lang = useLanguageState(); const value = { auth, theme, lang }; return ( <AppContext.Provider value={value}> {children} </AppContext.Provider> ); }

Best Practices:

  • Related contexts ko combine karo
  • Compose function banao reusability ke liye
  • Provider components ko separate file mein rakho
  • Documentation maintain karo kis context ka kya use hai

Q6. Context API mein performance optimization ke liye useMemo aur useCallback kab use karein? (Advanced) โ–ผ

Answer:

Problem: Har render pe context value naya object ban jata hai, jisse sabhi consumers re-render hote hain.

useMemo for Context Value:

// โŒ Bad: Har render pe naya object <UserContext.Provider value={{ user, setUser }}> // โœ… Good: Memoized value const value = useMemo( () => ({ user, setUser }), [user] // Only recreate when user changes ); <UserContext.Provider value={value}>

useCallback for Functions:

function AuthProvider({ children }) { const [user, setUser] = useState(null); // โŒ Bad: Har render pe naya function const login = (credentials) => { // login logic }; // โœ… Good: Memoized function const login = useCallback((credentials) => { // login logic setUser(userData); }, []); // Empty deps if no external dependencies const logout = useCallback(() => { setUser(null); }, []); const value = useMemo( () => ({ user, login, logout }), [user, login, logout] ); return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; }

Complete Optimized Example:

function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); // Memoize functions const toggleTheme = useCallback(() => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }, []); const setCustomTheme = useCallback((newTheme) => { setTheme(newTheme); }, []); // Memoize entire context value const value = useMemo( () => ({ theme, toggleTheme, setCustomTheme }), [theme, toggleTheme, setCustomTheme] ); return ( <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> ); }

When to Use:

  • useMemo: Context value objects, computed values, expensive calculations
  • useCallback: Functions passed in context, event handlers, API calls
  • Don't overuse: Simple values (strings, numbers) don't need memoization

Hinglish: Context value mein object ya function pass kar rahe ho? useMemo/useCallback use karo. Warna har render pe naya reference banega aur sabhi components re-render honge. But simple values ke liye over-optimize mat karo!

Q7. Context API ke saath TypeScript use karte waqt type safety kaise ensure karein? (Expert) โ–ผ

Answer:

Complete TypeScript Implementation:

// 1. Define types for context value interface User { id: string; name: string; email: string; role: 'admin' | 'user'; } interface AuthContextType { user: User | null; loading: boolean; login: (credentials: LoginCredentials) => Promise<void>; logout: () => void; isAuthenticated: boolean; } interface LoginCredentials { email: string; password: string; } // 2. Create context with type const AuthContext = createContext<AuthContextType | undefined>( undefined ); // 3. Provider with proper typing export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState(true); const login = useCallback( async (credentials: LoginCredentials) => { try { const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials) }); const userData: User = await response.json(); setUser(userData); } catch (error) { console.error(error); } }, [] ); const logout = useCallback(() => { setUser(null); }, []); const value: AuthContextType = useMemo( () => ({ user, loading, login, logout, isAuthenticated: !!user }), [user, loading, login, logout] ); return ( <AuthContext.Provider value={value}> {children} </AuthContext.Provider> ); } // 4. Custom hook with type safety export function useAuth(): AuthContextType { const context = useContext(AuthContext); if (context === undefined) { throw new Error( 'useAuth must be used within AuthProvider' ); } return context; } // 5. Usage with full type safety function Profile() { const { user, logout } = useAuth(); // Fully typed! if (!user) { return <div>Please login</div>; } return ( <div> <h1>{user.name}</h1> // TypeScript knows user properties <p>{user.email}</p> <p>Role: {user.role}</p> <button onClick={logout}>Logout</button> </div> ); }

Advanced: Generic Context Factory:

// Reusable context creator with types function createCtx<T>() { const ctx = createContext<T | undefined>(undefined); function useCtx() { const c = useContext(ctx); if (!c) throw new Error('useCtx must be inside Provider'); return c; } return [useCtx, ctx.Provider] as const; } // Usage const [useTheme, ThemeProvider] = createCtx<ThemeContextType>();

Benefits:

  • Autocomplete in IDE
  • Compile-time error checking
  • Better refactoring support
  • Self-documenting code
  • Prevents runtime errors

๐Ÿ“ Quick Summary

  • โœ… Context API: Prop drilling problem solve karta hai
  • โœ… Three Steps: Create โ†’ Provide โ†’ Consume (useContext)
  • โœ… Re-renders: Split contexts, useMemo, React.memo use karo
  • โœ… vs Redux: Small apps = Context, Large apps = Redux
  • โœ… Best For: Theme, Auth, Language, UI state
  • โœ… Optimization: useMemo for values, useCallback for functions
  • โœ… Custom Hooks: Har context ke liye custom hook banao
  • โœ… Don't Overuse: Har choti cheez ke liye context mat banao