๐ŸŽจ Advanced React Component Patterns

Master karo professional React patterns aur banao scalable applications!

๐Ÿ“š Component Patterns Kya Hain?

Component Patterns wo proven solutions hain jo common problems ko solve karte hain React applications mein. Ye patterns aapko help karte hain:

  • ๐Ÿ”„ Reusability: Code ko multiple jagah use kar sako
  • ๐ŸŽฏ Flexibility: Components ko easily customize kar sako
  • ๐Ÿ“ฆ Maintainability: Code ko maintain karna easy ho jaye
  • ๐Ÿงฉ Composition: Chhote components se bade components banao
  • โšก Performance: Efficient aur optimized code likho
๐Ÿ’ก Key Insight: Patterns sikhne se aap better architect ban sakte ho aur production-ready code likh sakte ho jo industry standards follow karta hai.

๐ŸŽญ Higher-Order Components

Components ko wrap karke extra functionality add karo

๐ŸŽช Render Props

Function as prop pass karke rendering logic share karo

๐Ÿงฉ Compound Components

Related components ko group karke implicit state share karo

๐ŸŽฎ Controlled vs Uncontrolled

Form state management ke different approaches

๐ŸŒ Provider Pattern

Context API se global state management

โš™๏ธ State Reducer Pattern

Complex state logic ko control karo

๐Ÿ‘ป Headless Components

Logic aur UI ko separate karo

๐ŸŽญ Higher-Order Components (HOCs)

Higher-Order Component (HOC) ek function hai jo ek component leta hai aur ek naya enhanced component return karta hai. Ye component reusability ke liye bahut powerful pattern hai.

Simple words mein: Ek wrapper function jo aapke component ko superpowers deta hai! ๐Ÿฆธโ€โ™‚๏ธ

Definition: A Higher-Order Component is a function that takes a component and returns a new component with additional props or behavior.

Basic HOC Example

// withLoading HOC - Loading functionality add karta hai function withLoading(Component) { return function WithLoadingComponent({ isLoading, ...props }) { if (isLoading) { return <div>Loading...</div>; } return <Component {...props} />; }; } // Original Component function UserList({ users }) { return ( <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ); } // Enhanced Component with loading const UserListWithLoading = withLoading(UserList); // Usage <UserListWithLoading isLoading={true} users={[]} />

Advanced HOC - Authentication

// withAuth HOC - Authentication check karta hai function withAuth(Component) { return function WithAuthComponent(props) { const { isAuthenticated, user } = useAuth(); if (!isAuthenticated) { return <Navigate to="/login" />; } return <Component {...props} user={user} />; }; } // Protected Component function Dashboard({ user }) { return <h1>Welcome, {user.name}!</h1>; } // Enhanced with authentication const ProtectedDashboard = withAuth(Dashboard);
๐ŸŽฎ Interactive HOC Demo


โœ… Advantages

  • Code reusability bahut achi
  • Cross-cutting concerns handle kar sakte ho
  • Component logic ko separate kar sakte ho
  • Multiple HOCs compose kar sakte ho

โŒ Disadvantages

  • Wrapper hell ho sakta hai
  • Props collision ka risk
  • Debugging mushkil ho sakti hai
  • Static methods copy nahi hote

Multiple HOCs Composition

// Multiple HOCs ko compose karna import { compose } from 'redux'; // ya lodash/flowRight const enhance = compose( withAuth, withLoading, withErrorBoundary, withAnalytics ); const EnhancedComponent = enhance(MyComponent); // Ya manually const EnhancedComponent = withAuth( withLoading( withErrorBoundary( withAnalytics(MyComponent) ) ) );

๐ŸŽช Render Props Pattern

Render Props ek technique hai jisme aap ek function ko prop ke through pass karte ho jo batata hai ki component ko kya render karna hai. Ye pattern logic sharing ke liye bahut useful hai.

Simple analogy: Aap chef ko recipe dete ho (function), aur chef dish banata hai (render)! ๐Ÿ‘จโ€๐Ÿณ

Definition: A component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.

Basic Render Props Example

// Mouse Tracker Component with Render Props class MouseTracker extends React.Component { state = { x: 0, y: 0 }; handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }); }; render() { return ( <div onMouseMove={this.handleMouseMove}> {this.props.render(this.state)} </div> ); } } // Usage - Different rendering logic <MouseTracker render={({ x, y }) => ( <h1>Mouse position: {x}, {y}</h1> )} /> <MouseTracker render={({ x, y }) => ( <div style={{ position: 'absolute', left: x, top: y }}> ๐ŸŽฏ </div> )} />

Modern Approach with Children Function

// Using children as function (cleaner syntax) function DataFetcher({ url, children }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then(res => res.json()) .then(data => { setData(data); setLoading(false); }) .catch(err => { setError(err); setLoading(false); }); }, [url]); return children({ data, loading, error }); } // Usage <DataFetcher url="/api/users"> {({ data, loading, error }) => { if (loading) return <Spinner />; if (error) return <Error message={error.message} />; return <UserList users={data} />; }} </DataFetcher>
๐ŸŽฎ Interactive Render Props Demo

Move your mouse over the box below:

๐ŸŽฏ

โœ… Advantages

  • Bahut flexible aur dynamic
  • Props collision nahi hota
  • Runtime pe rendering decide kar sakte ho
  • TypeScript ke saath better type safety

โŒ Disadvantages

  • Callback hell ho sakta hai
  • Syntax thoda verbose hai
  • Performance issues (inline functions)
  • Hooks ne isko mostly replace kar diya

Render Props vs Hooks

// Render Props approach <MouseTracker> {({ x, y }) => <Display x={x} y={y} />} </MouseTracker> // Hooks approach (Modern & Preferred) function Display() { const { x, y } = useMousePosition(); return <div>{x}, {y}</div>; } // Custom Hook function useMousePosition() { const [position, setPosition] = useState({ x: 0, y: 0 }); useEffect(() => { const handleMove = (e) => { setPosition({ x: e.clientX, y: e.clientY }); }; window.addEventListener('mousemove', handleMove); return () => window.removeEventListener('mousemove', handleMove); }, []); return position; }

๐Ÿงฉ Compound Components Pattern

Compound Components ek pattern hai jisme multiple components milkar ek single functionality provide karte hain. Ye components implicit state share karte hain aur ek dusre ke saath communicate karte hain.

Real-world example: HTML ke <select> aur <option> tags ki tarah! ๐ŸŽฏ

Definition: Compound components are a set of components that work together to form a complete UI, sharing implicit state through React Context.

Classic Example - Tabs Component

// Tabs Compound Component const TabsContext = React.createContext(); function Tabs({ children, defaultValue }) { const [activeTab, setActiveTab] = useState(defaultValue); return ( <TabsContext.Provider value={{ activeTab, setActiveTab }}> <div className="tabs">{children}</div> </TabsContext.Provider> ); } function TabList({ children }) { return <div className="tab-list">{children}</div>; } function Tab({ value, children }) { const { activeTab, setActiveTab } = useContext(TabsContext); const isActive = activeTab === value; return ( <button className={isActive ? 'tab active' : 'tab'} onClick={() => setActiveTab(value)} > {children} </button> ); } function TabPanel({ value, children }) { const { activeTab } = useContext(TabsContext); return activeTab === value ? <div>{children}</div> : null; } // Compound API Tabs.List = TabList; Tabs.Tab = Tab; Tabs.Panel = TabPanel; // Usage - Very intuitive! <Tabs defaultValue="profile"> <Tabs.List> <Tabs.Tab value="profile">Profile</Tabs.Tab> <Tabs.Tab value="settings">Settings</Tabs.Tab> </Tabs.List> <Tabs.Panel value="profile"> Profile Content </Tabs.Panel> <Tabs.Panel value="settings"> Settings Content </Tabs.Panel> </Tabs>
๐ŸŽฎ Interactive Compound Components Demo

Home Content

Welcome to the home page! Ye compound components ka example hai.

Profile Content

Your profile information would be displayed here.

Settings Content

Configure your application settings here.

Another Example - Accordion

// Accordion Compound Component function Accordion({ children, allowMultiple = false }) { const [openItems, setOpenItems] = useState([]); const toggleItem = (value) => { if (allowMultiple) { setOpenItems(prev => prev.includes(value) ? prev.filter(item => item !== value) : [...prev, value] ); } else { setOpenItems(prev => prev.includes(value) ? [] : [value] ); } }; return ( <AccordionContext.Provider value={{ openItems, toggleItem }}> {children} </AccordionContext.Provider> ); } function AccordionItem({ value, children }) { return <div className="accordion-item">{children}</div>; } function AccordionTrigger({ value, children }) { const { openItems, toggleItem } = useContext(AccordionContext); const isOpen = openItems.includes(value); return ( <button onClick={() => toggleItem(value)}> {children} {isOpen ? 'โ–ผ' : 'โ–ถ'} </button> ); } function AccordionContent({ value, children }) { const { openItems } = useContext(AccordionContext); return openItems.includes(value) ? <div>{children}</div> : null; } // Usage <Accordion allowMultiple> <AccordionItem value="item1"> <AccordionTrigger value="item1">Question 1</AccordionTrigger> <AccordionContent value="item1">Answer 1</AccordionContent> </AccordionItem> </Accordion>

โœ… Advantages

  • API bahut intuitive aur readable
  • Flexible composition
  • State automatically share hota hai
  • Separation of concerns

โŒ Disadvantages

  • Implementation complex ho sakta hai
  • JSX structure rigid hona chahiye
  • Context overhead
  • Learning curve thoda steep

๐ŸŽฎ Controlled vs Uncontrolled Components

Form elements ko handle karne ke do main approaches hain React mein. Ye decide karta hai ki state kahan rahega - React mein ya DOM mein.

Key Difference: Controlled components mein React state source of truth hai, uncontrolled mein DOM source of truth hai.

Controlled Components

Controlled Component mein form data React component ki state se control hota hai. Har keystroke pe state update hoti hai.

// Controlled Component Example function ControlledForm() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const handleSubmit = (e) => { e.preventDefault(); console.log({ name, email }); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" /> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" /> <button type="submit">Submit</button> </form> ); } // Benefits: // โœ… Instant validation // โœ… Conditional disabling // โœ… Format enforcement // โœ… Dynamic feedback

Uncontrolled Components

Uncontrolled Component mein form data DOM ke through handle hota hai. Refs use karke values access karte hain.

// Uncontrolled Component Example function UncontrolledForm() { const nameRef = useRef(); const emailRef = useRef(); const handleSubmit = (e) => { e.preventDefault(); console.log({ name: nameRef.current.value, email: emailRef.current.value }); }; return ( <form onSubmit={handleSubmit}> <input type="text" ref={nameRef} defaultValue="" placeholder="Name" /> <input type="email" ref={emailRef} defaultValue="" placeholder="Email" /> <button type="submit">Submit</button> </form> ); } // Benefits: // โœ… Less code // โœ… Better performance (no re-renders) // โœ… Easy integration with non-React code // โœ… Good for simple forms
๐ŸŽฎ Controlled vs Uncontrolled Demo

Controlled Form

Current Value: ""

Character Count: 0

โœ… Real-time validation possible

Uncontrolled Form

Value: Not retrieved yet

โš ๏ธ Value only accessed when needed

Feature Controlled Uncontrolled
State Location React State DOM
Access Method State variable Refs
Re-renders On every change No re-renders
Validation Real-time On submit
Performance Slower (more renders) Faster
Use Case Complex forms, validation Simple forms, file uploads

When to Use What?

Controlled Components use karo jab:

  • Real-time validation chahiye
  • Conditional logic based on input
  • Dynamic form fields
  • Format enforcement (phone, credit card)

Uncontrolled Components use karo jab:

  • Simple forms with minimal logic
  • File uploads
  • Integration with non-React code
  • Performance critical scenarios

๐ŸŒ Provider Pattern

Provider Pattern React Context API use karke global state management provide karta hai. Ye prop drilling problem ko solve karta hai.

Analogy: Ek central warehouse se sabko supplies milti hain, har level pe pass karne ki zarurat nahi! ๐Ÿ“ฆ

Definition: Provider Pattern uses React Context to make data available to all components in a tree without explicitly passing props through every level.

Basic Provider Implementation

// Theme Provider Example const ThemeContext = createContext(); function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; const value = { theme, toggleTheme }; return ( <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> ); } // Custom Hook for easy access function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within ThemeProvider'); } return context; } // Usage in App function App() { return ( <ThemeProvider> <Header /> <Main /> <Footer /> </ThemeProvider> ); } // Usage in any nested component function Header() { const { theme, toggleTheme } = useTheme(); return ( <header className={theme}> <button onClick={toggleTheme}> Toggle Theme </button> </header> ); }

Advanced Provider - Auth Example

// Authentication Provider const AuthContext = createContext(); function AuthProvider({ children }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Check if user is logged in const token = localStorage.getItem('token'); if (token) { fetchUser(token).then(setUser).finally(() => setLoading(false)); } else { setLoading(false); } }, []); const login = async (credentials) => { const { user, token } = await api.login(credentials); localStorage.setItem('token', token); setUser(user); }; const logout = () => { localStorage.removeItem('token'); setUser(null); }; const value = { user, loading, login, logout, isAuthenticated: !!user }; return ( <AuthContext.Provider value={value}> {children} </AuthContext.Provider> ); } function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within AuthProvider'); } return context; } // Protected Route Component function ProtectedRoute({ children }) { const { isAuthenticated, loading } = useAuth(); if (loading) return <Spinner />; if (!isAuthenticated) return <Navigate to="/login" />; return children; }
๐ŸŽฎ Interactive Provider Pattern Demo

Current Theme: Light

Sample Content

This content changes based on the theme from Provider!

No prop drilling needed - any component can access theme.

Multiple Providers Composition

// Composing multiple providers function AppProviders({ children }) { return ( <AuthProvider> <ThemeProvider> <LanguageProvider> <NotificationProvider> {children} </NotificationProvider> </LanguageProvider> </ThemeProvider> </AuthProvider> ); } // Usage function App() { return ( <AppProviders> <Router> <Routes /> </Router> </AppProviders> ); }

โœ… Advantages

  • Prop drilling eliminate ho jata hai
  • Global state management easy
  • Clean component hierarchy
  • Easy to test and maintain

โŒ Disadvantages

  • Performance issues (unnecessary re-renders)
  • Context value change pe sab consumers re-render
  • Debugging mushkil ho sakti hai
  • Provider hell ho sakta hai

โšก Performance Optimization Tips

  • Split contexts: Ek hi context mein sab kuch mat dalo
  • Memoize value: useMemo use karo context value ke liye
  • Separate state: Frequently changing aur stable state ko alag rakho
  • Use selectors: Sirf required data access karo

โš™๏ธ State Reducer Pattern

State Reducer Pattern users ko state management logic ko control karne ki power deta hai. Ye pattern Redux se inspired hai aur complex state logic ke liye perfect hai.

Power: Component ka behavior customize kar sakte ho without modifying component code! ๐ŸŽ›๏ธ

Definition: State Reducer Pattern allows users to invert control over state management by providing their own reducer function to override default behavior.

Basic State Reducer Example

// Counter with State Reducer function useCounter({ initialCount = 0, reducer = (state, action) => state // default reducer }) { const [count, setCount] = useReducer( (state, action) => { // User's custom reducer gets first chance const changes = reducer(state, action); // Default behavior switch (action.type) { case 'INCREMENT': return changes ?? state + 1; case 'DECREMENT': return changes ?? state - 1; case 'RESET': return changes ?? initialCount; default: return state; } }, initialCount ); const increment = () => setCount({ type: 'INCREMENT' }); const decrement = () => setCount({ type: 'DECREMENT' }); const reset = () => setCount({ type: 'RESET' }); return { count, increment, decrement, reset }; } // Usage 1: Default behavior function Counter1() { const { count, increment, decrement } = useCounter({ initialCount: 0 }); return ( <div> <p>Count: {count}</p> <button onClick={increment}>+</button> <button onClick={decrement}>-</button> </div> ); } // Usage 2: Custom behavior - Max limit function Counter2() { const { count, increment, decrement } = useCounter({ initialCount: 0, reducer: (state, action) => { if (action.type === 'INCREMENT' && state >= 10) { return state; // Don't increment beyond 10 } if (action.type === 'DECREMENT' && state <= 0) { return state; // Don't decrement below 0 } return undefined; // Use default behavior } }); return ( <div> <p>Count: {count} (Max: 10)</p> <button onClick={increment}>+</button> <button onClick={decrement}>-</button> </div> ); }

Advanced Example - Toggle with State Reducer

// Toggle Component with State Reducer function useToggle({ initialOn = false, reducer = (state, action) => action.changes // default }) { const [state, dispatch] = useReducer((state, action) => { const changes = { on: !state.on }; // Let user's reducer modify changes const userChanges = reducer(state, { ...action, changes }); return userChanges ?? changes; }, { on: initialOn }); const toggle = () => dispatch({ type: 'TOGGLE' }); const setOn = () => dispatch({ type: 'SET_ON' }); const setOff = () => dispatch({ type: 'SET_OFF' }); return { on: state.on, toggle, setOn, setOff }; } // Usage: Toggle with click limit function LimitedToggle() { const [clickCount, setClickCount] = useState(0); const { on, toggle } = useToggle({ reducer: (state, action) => { if (clickCount >= 4) { return state; // No more toggles after 4 clicks } return action.changes; } }); const handleToggle = () => { toggle(); setClickCount(c => c + 1); }; return ( <div> <button onClick={handleToggle}> {on ? 'ON' : 'OFF'} </button> <p>Clicks: {clickCount}/4</p> </div> ); }
๐ŸŽฎ Interactive State Reducer Demo
Normal Counter

0

Limited Counter (0-10)

0

Custom reducer with limits!

โœ… Advantages

  • Inversion of control - users customize behavior
  • Component reusability bahut high
  • Complex state logic handle kar sakte ho
  • Predictable state updates

โŒ Disadvantages

  • API complex ho sakta hai
  • Learning curve steep hai
  • Over-engineering ka risk
  • Documentation zaroori hai

๐ŸŽฏ When to Use State Reducer?

  • Jab users ko component behavior customize karni ho
  • Complex state transitions handle karne ke liye
  • Library/framework components banate waqt
  • Jab default behavior sufficient nahi hai

๐Ÿ‘ป Headless Components Pattern

Headless Components wo components hain jo logic provide karte hain but UI nahi. Ye pattern maximum flexibility deta hai styling aur structure ke liye.

Philosophy: "Bring your own UI" - Logic hum denge, design tum karo! ๐ŸŽจ

Definition: Headless components provide functionality and behavior without prescribing any specific UI, allowing complete control over rendering and styling.

Basic Headless Component Example

// Headless Dropdown Component function useDropdown() { const [isOpen, setIsOpen] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const dropdownRef = useRef(null); // Close on outside click useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setIsOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); // Keyboard navigation const handleKeyDown = (event) => { if (event.key === 'Escape') { setIsOpen(false); } }; return { isOpen, selectedItem, dropdownRef, getToggleProps: () => ({ onClick: () => setIsOpen(!isOpen), onKeyDown: handleKeyDown, 'aria-expanded': isOpen, 'aria-haspopup': true }), getMenuProps: () => ({ role: 'menu', hidden: !isOpen }), getItemProps: (item) => ({ role: 'menuitem', onClick: () => { setSelectedItem(item); setIsOpen(false); } }) }; } // Usage 1: Simple Dropdown function SimpleDropdown() { const { isOpen, selectedItem, dropdownRef, getToggleProps, getMenuProps, getItemProps } = useDropdown(); const items = ['Apple', 'Banana', 'Orange']; return ( <div ref={dropdownRef}> <button {...getToggleProps()}> {selectedItem || 'Select fruit'} โ–ผ </button> <ul {...getMenuProps()}> {items.map(item => ( <li key={item} {...getItemProps(item)}> {item} </li> ))} </ul> </div> ); } // Usage 2: Fancy Dropdown (Same logic, different UI!) function FancyDropdown() { const { isOpen, selectedItem, dropdownRef, getToggleProps, getMenuProps, getItemProps } = useDropdown(); const items = [ { id: 1, name: 'Apple', icon: '๐ŸŽ' }, { id: 2, name: 'Banana', icon: '๐ŸŒ' }, { id: 3, name: 'Orange', icon: '๐ŸŠ' } ]; return ( <div ref={dropdownRef} className="fancy-dropdown"> <div className="fancy-trigger" {...getToggleProps()}> {selectedItem ? ( <>{selectedItem.icon} {selectedItem.name}</> ) : ( 'Choose your favorite fruit' )} </div> <div className="fancy-menu" {...getMenuProps()}> {items.map(item => ( <div key={item.id} className="fancy-item" {...getItemProps(item)} > <span className="icon">{item.icon}</span> <span className="name">{item.name}</span> </div> ))} </div> </div> ); }

Real-World Example - Headless Table

// Headless Table Hook function useTable({ data, columns }) { const [sortConfig, setSortConfig] = useState(null); const [selectedRows, setSelectedRows] = useState(new Set()); const sortedData = useMemo(() => { if (!sortConfig) return data; return [...data].sort((a, b) => { const aVal = a[sortConfig.key]; const bVal = b[sortConfig.key]; if (aVal < bVal) return sortConfig.direction === 'asc' ? -1 : 1; if (aVal > bVal) return sortConfig.direction === 'asc' ? 1 : -1; return 0; }); }, [data, sortConfig]); const handleSort = (key) => { setSortConfig(prev => ({ key, direction: prev?.key === key && prev.direction === 'asc' ? 'desc' : 'asc' })); }; const toggleRowSelection = (id) => { setSelectedRows(prev => { const newSet = new Set(prev); if (newSet.has(id)) { newSet.delete(id); } else { newSet.add(id); } return newSet; }); }; return { data: sortedData, columns, sortConfig, selectedRows, getTableProps: () => ({ role: 'table' }), getHeaderProps: (column) => ({ onClick: () => handleSort(column.key), 'aria-sort': sortConfig?.key === column.key ? sortConfig.direction : 'none' }), getRowProps: (row) => ({ 'aria-selected': selectedRows.has(row.id), onClick: () => toggleRowSelection(row.id) }), getCellProps: () => ({ role: 'cell' }) }; } // Usage: Custom styled table function DataTable() { const data = [ { id: 1, name: 'John', age: 30, city: 'NYC' }, { id: 2, name: 'Jane', age: 25, city: 'LA' }, { id: 3, name: 'Bob', age: 35, city: 'Chicago' } ]; const columns = [ { key: 'name', label: 'Name' }, { key: 'age', label: 'Age' }, { key: 'city', label: 'City' } ]; const { data: sortedData, columns: tableColumns, getTableProps, getHeaderProps, getRowProps, getCellProps } = useTable({ data, columns }); return ( <table {...getTableProps()}> <thead> <tr> {tableColumns.map(col => ( <th key={col.key} {...getHeaderProps(col)}> {col.label} </th> ))} </tr> </thead> <tbody> {sortedData.map(row => ( <tr key={row.id} {...getRowProps(row)}> {tableColumns.map(col => ( <td key={col.key} {...getCellProps()}> {row[col.key]} </td> ))} </tr> ))} </tbody> </table> ); }
๐ŸŽฎ Interactive Headless Component Demo

Same logic, different UIs! Click to see variations:

Simple dropdown - basic styling

๐ŸŽ Apple

Fancy dropdown - gradient styling

Apple โ–ผ

Minimal dropdown - borderless design

๐Ÿ’ก Same headless logic powers all three UIs! Ye flexibility headless components ki power hai.

โœ… Advantages

  • Complete styling freedom
  • Maximum reusability
  • Accessibility built-in
  • Framework agnostic logic
  • Easy to test

โŒ Disadvantages

  • More boilerplate code
  • Steeper learning curve
  • No default UI (extra work)
  • Can be overkill for simple cases

๐ŸŒŸ Popular Headless Libraries

Headless UI

Tailwind team ka library - accessible components

Radix UI

Unstyled, accessible components

React Table

Headless table library

Downshift

Headless autocomplete/dropdown

๐Ÿ“Š Pattern Comparison & When to Use

Pattern Best For Complexity Modern Alternative
HOC Cross-cutting concerns, authentication Medium Custom Hooks
Render Props Dynamic rendering logic Medium Custom Hooks
Compound Components Related components, UI libraries High Still relevant!
Controlled Forms with validation Low React Hook Form
Provider Global state, theming Low-Medium Still relevant!
State Reducer Complex state, libraries High Still relevant!
Headless Maximum flexibility, design systems High Still relevant!

๐ŸŽฏ Decision Tree: Kaunsa Pattern Use Karein?

Need to share logic?
โ†’
Custom Hook
Need global state?
โ†’
Provider Pattern
Building UI library?
โ†’
Compound + Headless
Need customizable behavior?
โ†’
State Reducer

๐ŸŽฏ Interview Questions

1. HOC aur Custom Hooks mein kya difference hai? Kab kaunsa use karein?
Medium โ–ผ

Answer:

Higher-Order Components (HOC):

  • Component ko wrap karke new component return karta hai
  • Props ke through data pass hota hai
  • Component tree mein extra layer add hota hai
  • Class aur functional dono components ke saath kaam karta hai

Custom Hooks:

  • Logic ko reuse karne ka modern way
  • Direct values return karta hai, component nahi
  • No wrapper hell, cleaner code
  • Sirf functional components ke saath

When to use:

โœ… Custom Hooks prefer karo - Modern, cleaner, aur React team ka recommendation

โš ๏ธ HOC use karo - Legacy code maintain karte waqt ya jab component wrapping zaroori ho

// HOC const Enhanced = withAuth(Component); // Custom Hook (Better!) function Component() { const { user, isAuth } = useAuth(); // Direct use, no wrapping }
2. Compound Components pattern ko implement kaise karenge? Example ke saath explain karo.
Hard โ–ผ

Answer:

Compound Components pattern mein hum Context API use karke related components ko implicit state share karate hain.

// Step 1: Create Context const AccordionContext = createContext(); // Step 2: Parent Component with Provider function Accordion({ children, allowMultiple = false }) { const [openItems, setOpenItems] = useState([]); const toggle = (id) => { setOpenItems(prev => { if (allowMultiple) { return prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]; } return prev.includes(id) ? [] : [id]; }); }; return ( <AccordionContext.Provider value={{ openItems, toggle }}> {children} </AccordionContext.Provider> ); } // Step 3: Child Components function AccordionItem({ id, children }) { return <div className="item">{children}</div>; } function AccordionHeader({ id, children }) { const { openItems, toggle } = useContext(AccordionContext); const isOpen = openItems.includes(id); return ( <button onClick={() => toggle(id)}> {children} {isOpen ? 'โ–ผ' : 'โ–ถ'} </button> ); } function AccordionPanel({ id, children }) { const { openItems } = useContext(AccordionContext); return openItems.includes(id) ? <div>{children}</div> : null; } // Step 4: Attach to parent Accordion.Item = AccordionItem; Accordion.Header = AccordionHeader; Accordion.Panel = AccordionPanel; // Usage <Accordion allowMultiple> <Accordion.Item id="1"> <Accordion.Header id="1">Question 1</Accordion.Header> <Accordion.Panel id="1">Answer 1</Accordion.Panel> </Accordion.Item> </Accordion>

Key Points:

  • Context se implicit state sharing
  • Flexible composition
  • Intuitive API
  • Components tightly coupled but loosely structured
3. Controlled vs Uncontrolled components - performance implications kya hain?
Medium โ–ผ

Answer:

Controlled Components:

  • โŒ Performance Impact: Har keystroke pe component re-render hota hai
  • โŒ Large forms mein slow ho sakta hai
  • โœ… Real-time validation possible
  • โœ… Conditional logic easy

Uncontrolled Components:

  • โœ… Better Performance: No re-renders on input change
  • โœ… Large forms ke liye better
  • โŒ Validation sirf submit pe
  • โŒ Dynamic behavior mushkil

Performance Optimization Tips:

// 1. Debouncing for controlled inputs const [value, setValue] = useState(''); const debouncedValue = useDebounce(value, 300); // 2. Use React Hook Form (best of both worlds) const { register } = useForm(); <input {...register('email')} /> // 3. Split large forms into smaller components // Each section manages its own state // 4. Use uncontrolled for simple forms const nameRef = useRef(); // Access only on submit

Recommendation: Modern apps mein React Hook Form use karo - ye uncontrolled approach use karta hai but controlled jaise features deta hai!

4. Provider Pattern mein performance issues kaise avoid karein?
Hard โ–ผ

Answer:

Provider Pattern mein main problem ye hai ki context value change hone pe saare consumers re-render ho jate hain, chahe unhe us value ki zarurat ho ya nahi.


Solutions:

1. Split Contexts (Most Important!):

// โŒ Bad - Everything in one context const AppContext = createContext(); function AppProvider({ children }) { const [user, setUser] = useState(null); const [theme, setTheme] = useState('light'); const [notifications, setNotifications] = useState([]); // Theme change pe sab re-render! } // โœ… Good - Separate contexts const UserContext = createContext(); const ThemeContext = createContext(); const NotificationContext = createContext(); // Ab sirf relevant components re-render honge

2. Memoize Context Value:

function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); // โœ… Memoize to prevent unnecessary re-renders const value = useMemo(() => ({ theme, setTheme }), [theme]); return ( <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> ); }

3. Use Selectors:

// Custom hook with selector function useUser(selector = (state) => state) { const context = useContext(UserContext); return selector(context); } // Usage - only re-render when name changes function UserName() { const name = useUser(state => state.user.name); return <div>{name}</div>; }

4. Separate State and Dispatch:

const StateContext = createContext(); const DispatchContext = createContext(); // Components jo sirf dispatch use karte hain // wo state changes pe re-render nahi honge function Button() { const dispatch = useContext(DispatchContext); // No re-render on state change! }

Best Practice: Frequently changing state aur stable state ko alag contexts mein rakho!

5. State Reducer Pattern ka real-world use case explain karo.
Hard โ–ผ

Answer:

Real-World Scenario: Ek reusable Modal component jo different apps mein different behavior chahiye.

// Modal with State Reducer function useModal({ initialOpen = false, reducer = (state, action) => action.changes }) { const [state, dispatch] = useReducer((state, action) => { const changes = (() => { switch (action.type) { case 'OPEN': return { isOpen: true }; case 'CLOSE': return { isOpen: false }; case 'TOGGLE': return { isOpen: !state.isOpen }; default: return state; } })(); // User's custom reducer can override return reducer(state, { ...action, changes }) ?? changes; }, { isOpen: initialOpen }); return { isOpen: state.isOpen, open: () => dispatch({ type: 'OPEN' }), close: () => dispatch({ type: 'CLOSE' }), toggle: () => dispatch({ type: 'TOGGLE' }) }; } // Use Case 1: Normal Modal (Default behavior) function NormalModal() { const { isOpen, open, close } = useModal(); return ( <> <button onClick={open}>Open</button> {isOpen && <Modal onClose={close} />} </> ); } // Use Case 2: Confirmation Required Modal function ConfirmModal() { const [hasUnsavedChanges, setHasUnsavedChanges] = useState(true); const { isOpen, open, close } = useModal({ reducer: (state, action) => { // Prevent closing if unsaved changes if (action.type === 'CLOSE' && hasUnsavedChanges) { const confirmed = window.confirm('Unsaved changes. Close anyway?'); if (!confirmed) { return state; // Don't close } } return action.changes; // Use default behavior } }); return ( <> <button onClick={open}>Open</button> {isOpen && ( <Modal onClose={close}> <input onChange={() => setHasUnsavedChanges(true)} /> </Modal> )} </> ); } // Use Case 3: Analytics Tracking Modal function AnalyticsModal() { const { isOpen, open, close } = useModal({ reducer: (state, action) => { // Track every modal interaction if (action.type === 'OPEN') { analytics.track('Modal Opened'); } if (action.type === 'CLOSE') { analytics.track('Modal Closed'); } return action.changes; } }); return <Modal isOpen={isOpen} onClose={close} />; }

Benefits:

  • Same component, different behaviors
  • No need to modify original component
  • Users control the logic
  • Perfect for library authors
6. Headless Components ka main advantage kya hai? Kab use nahi karna chahiye?
Medium โ–ผ

Answer:

Main Advantages:

  • ๐ŸŽจ Complete Styling Freedom: Apni design system use kar sakte ho
  • โ™ฟ Accessibility Built-in: Logic mein accessibility handle hoti hai
  • ๐Ÿ”„ Maximum Reusability: Same logic, infinite UIs
  • ๐Ÿงช Easy Testing: Logic aur UI separately test kar sakte ho
  • ๐Ÿ“ฆ Framework Agnostic: Logic ko kahi bhi use kar sakte ho

When NOT to use:

  • โŒ Simple components jo rarely customize hote hain
  • โŒ Jab ready-made UI library sufficient hai
  • โŒ Tight deadlines aur limited resources
  • โŒ Team mein headless pattern ka experience nahi
  • โŒ Prototype ya MVP bana rahe ho

Example Comparison:

// Regular Component (Opinionated UI) <Button variant="primary" size="large"> Click Me </Button> // Limited customization // Headless Component (Full Control) <Button> {({ isPressed, isHovered }) => ( <div className={myCustomStyles}> {isPressed ? '๐Ÿ‘‡' : isHovered ? '๐Ÿ‘†' : '๐Ÿ‘‰'} Click Me </div> )} </Button> // Unlimited customization

Best Use Cases:

  • Design systems aur component libraries
  • Complex interactive components (dropdowns, modals, tables)
  • Jab multiple brands/themes support karni ho
  • Accessibility critical applications
7. Modern React mein kaunse patterns still relevant hain aur kaunse obsolete ho gaye?
Easy โ–ผ

Answer:

โœ… Still Relevant & Recommended:

  • Compound Components: UI libraries ke liye perfect, intuitive API
  • Provider Pattern: Global state management ke liye essential
  • Headless Components: Design systems aur flexibility ke liye best
  • State Reducer: Complex state logic ke liye powerful
  • Controlled Components: Forms ke liye standard approach

โš ๏ธ Less Common (Better Alternatives Exist):

  • HOCs: Custom Hooks ne mostly replace kar diya
    // Old: HOC const Enhanced = withAuth(Component); // New: Custom Hook function Component() { const auth = useAuth(); }
  • Render Props: Custom Hooks cleaner alternative
    // Old: Render Props <Mouse> {({ x, y }) => <Display x={x} y={y} />} </Mouse> // New: Custom Hook function Display() { const { x, y } = useMouse(); }

๐Ÿš€ Modern Recommendations:

Need Use This
Share logic Custom Hooks
Global state Context + Provider
Complex state useReducer + State Reducer
UI library Compound + Headless
Forms React Hook Form

Key Takeaway: Hooks ne bahut patterns ko simplify kar diya, but architectural patterns (Compound, Headless, Provider) still valuable hain!

๐ŸŽ“ Summary & Key Takeaways

๐Ÿ“ Pattern Selection Guide:

๐ŸŽฏ For Logic Sharing

Use Custom Hooks - Modern, clean, aur React team ka recommendation

๐ŸŒ For Global State

Use Provider Pattern - Context API ke saath perfect combination

๐Ÿงฉ For UI Libraries

Use Compound Components - Intuitive API aur flexible composition

๐Ÿ‘ป For Maximum Flexibility

Use Headless Components - Complete styling freedom

โš™๏ธ For Complex State

Use State Reducer - User-controlled behavior

๐ŸŽฎ For Forms

Use Controlled with validation or React Hook Form

๐Ÿ’ก Final Tips:

  • โœ… Patterns ko blindly follow mat karo - problem ko samjho pehle
  • โœ… Simple solutions prefer karo - over-engineering se bacho
  • โœ… Team ke experience level consider karo
  • โœ… Performance implications samjho
  • โœ… Modern alternatives explore karo (Hooks!)
  • โœ… Documentation aur examples zaroori hain