All topics

React Patterns

Common React patterns and best practices

1. Controlled vs Uncontrolled Components

beginner

Explain the difference between controlled and uncontrolled components in React. Provide examples of each and when you would use one over the other. What are the advantages and disadvantages of each approach?

javascript
// Controlled Component
function ControlledForm() {
  const [value, setValue] = useState("");
  
  const handleChange = (e) => {
    setValue(e.target.value);
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("Controlled value:", value);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text" 
        value={value} 
        onChange={handleChange} 
      />
      <button type="submit">Submit</button>
    </form>
  );
}

// Uncontrolled Component
function UncontrolledForm() {
  const inputRef = useRef(null);
  
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("Uncontrolled value:", inputRef.current.value);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text" 
        ref={inputRef} 
        defaultValue="initial" 
      />
      <button type="submit">Submit</button>
    </form>
  );
}

// When to use controlled:
// - Form validation in real-time
// - Dynamic form fields
// - Complex forms with conditional logic
// - When you need to manipulate the value before submission

// When to use uncontrolled:
// - Simple forms
// - File inputs (always uncontrolled)
// - Performance-critical forms with many inputs
// - When integrating with non-React code

Answer: Controlled Component: React state manages the input value Uncontrolled Component: DOM manages the input value via ref Use controlled for validation, dynamic behavior Use uncontrolled for simple forms, file inputs, performance

KEY DIFFERENCES: CONTROLLED COMPONENTS: - Value stored in React state - onChange updates state, re-renders component - Single source of truth - Enables real-time validation - Enables dynamic form behavior - Easier to test UNCONTROLLED COMPONENTS: - Value stored in DOM - Ref used to access value on submit - Less re-renders (better performance) - Simpler for basic forms - Required for file inputs - Can integrate with non-React libraries REAL-WORLD USE CASES: Controlled: - Search with autocomplete - Form with conditional fields - Multi-step forms - Complex validation Uncontrolled: - Simple contact form - File upload - Integration with jQuery plugins - Performance-critical tables with many inputs PERFORMANCE IMPACT: - Controlled: Re-renders on every keystroke - Uncontrolled: No re-renders until submit - For large forms, uncontrolled can be 10x faster BEST PRACTICES: - Default to controlled for most forms - Use uncontrolled when performance matters - File inputs must be uncontrolled - Consider hybrid approach for large forms ASKED AT: Meta, Google, Amazon, Airbnb (React fundamentals)

controlleduncontrolledformscomponents

2. Higher Order Components Pattern

intermediate

Implement a Higher Order Component (HOC) that adds loading state management to any component. The HOC should: 1. Show a spinner while data is loading 2. Pass loading state as a prop 3. Handle errors gracefully 4. Be reusable across different components Example usage: const UserProfileWithLoader = withLoader(UserProfile, fetchUserData);

javascript
function withLoader(WrappedComponent, fetchData) {
  return function WithLoaderComponent(props) {
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);
    
    useEffect(() => {
      const loadData = async () => {
        try {
          setLoading(true);
          const result = await fetchData(props);
          setData(result);
        } catch (err) {
          setError(err.message);
        } finally {
          setLoading(false);
        }
      };
      
      loadData();
    }, [props]);
    
    if (loading) {
      return <div className="spinner">Loading...</div>;
    }
    
    if (error) {
      return <div className="error">Error: {error}</div>;
    }
    
    return <WrappedComponent {...props} data={data} loading={loading} />;
  };
}

// Usage example
function UserProfile({ user, loading }) {
  if (loading) return <div>Loading user...</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

const fetchUserData = async ({ userId }) => {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
};

const UserProfileWithLoader = withLoader(UserProfile, fetchUserData);

// In parent component
function App() {
  return <UserProfileWithLoader userId={123} />;
}

// Alternative: Render Props version
function Loader({ fetchData, children }) {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetchData().then(setData).finally(() => setLoading(false));
  }, [fetchData]);
  
  return children({ loading, data });
}

Answer: HOC returns new component with loading state Shows spinner while loading, passes data as prop Handles errors gracefully Reusable across different components

HIGHER ORDER COMPONENTS: Functions that take a component and return an enhanced component. ADVANTAGES: - Code reuse across components - Separation of concerns - Can modify component behavior - Compatible with class and function components DISADVANTAGES: - Prop collisions possible - Can create wrapper hell - Harder to debug in DevTools - Less intuitive than hooks MODERN ALTERNATIVES: 1. Custom Hooks (preferred in modern React) 2. Render Props pattern 3. Component Composition USE CASES FOR HOC: - Authentication/Authorization - Logging/Analytics - Error boundaries - Loading states - Data fetching BEST PRACTICES: - Use meaningful displayName for debugging - Pass through unrelated props - Avoid prop name collisions - Consider using hooks for new code REAL-WORLD EXAMPLES: - React-Redux connect() - React Router withRouter() - Material-UI withStyles() HOOKS VS HOC: - Hooks: More flexible, less nesting - HOC: Works with class components - Both can achieve similar results ASKED AT: Meta, Netflix, Uber (legacy codebases)

hocpatternscompositionreusability

3. Custom Hook for Data Fetching with Cache

intermediate

Create a custom hook called useFetch that handles: 1. Data fetching with loading/error states 2. Caching responses to avoid duplicate requests 3. Automatic cleanup on unmount 4. Dependency-based refetching 5. Abort controller for canceling requests Example usage: const { data, loading, error } = useFetch("/api/users", { method: "GET" });

javascript
function useFetch(url, options = {}, dependencies = []) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  // Cache using useRef (could use Context/Redux for global cache)
  const cache = useRef({});
  
  useEffect(() => {
    const abortController = new AbortController();
    
    const fetchData = async () => {
      setLoading(true);
      setError(null);
      
      // Check cache first
      const cacheKey = url + JSON.stringify(options);
      if (cache.current[cacheKey]) {
        setData(cache.current[cacheKey]);
        setLoading(false);
        return;
      }
      
      try {
        const response = await fetch(url, {
          ...options,
          signal: abortController.signal
        });
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const result = await response.json();
        
        // Cache the result
        cache.current[cacheKey] = result;
        setData(result);
      } catch (err) {
        if (err.name !== "AbortError") {
          setError(err.message);
        }
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
    
    // Cleanup function
    return () => {
      abortController.abort();
    };
  }, [url, JSON.stringify(options), ...dependencies]);
  
  return { data, loading, error };
}

// Usage examples
function UserList() {
  const { data: users, loading, error } = useFetch("/api/users");
  
  if (loading) return <div>Loading users...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

// With dependencies
function UserProfile({ userId }) {
  const { data: user } = useFetch(
    `/api/users/${userId}`,
    { method: "GET" },
    [userId] // Refetch when userId changes
  );
}

// Advanced: Return refetch function
// Add to useFetch:
const [trigger, setTrigger] = useState(0);
const refetch = () => setTrigger(t => t + 1);
// Add trigger to dependencies

Answer: Custom hook returns { data, loading, error } Implements caching to avoid duplicate requests Uses AbortController for cleanup Refetches when dependencies change

CUSTOM HOOK PATTERN: Extract reusable logic from components into hooks. KEY FEATURES IMPLEMENTED: 1. CACHING: - Store responses in useRef - Avoid duplicate network requests - Simple in-memory cache - Could be enhanced with TTL 2. ABORT CONTROLLER: - Cancel requests on unmount - Prevent state updates on unmounted components - Avoid memory leaks 3. DEPENDENCY TRACKING: - Refetch when URL/options change - Manual refetch capability - Prevent infinite loops 4. ERROR HANDLING: - HTTP error status handling - Network error handling - Clean error states PERFORMANCE OPTIMIZATIONS: - useRef for cache (doesn't cause re-renders) - JSON.stringify for dependency comparison - AbortController for cleanup - Conditional fetching PRODUCTION CONSIDERATIONS: - Add retry logic with exponential backoff - Implement stale-while-revalidate - Add request deduplication - Consider using SWR or React Query ALTERNATIVE LIBRARIES: - React Query (TanStack Query) - SWR (Stale-While-Revalidate) - Apollo Client (GraphQL) - RTK Query (Redux Toolkit) USE CASES: - API data fetching - Form submissions - Real-time updates - Paginated data ASKED AT: Meta, Google, Netflix (modern React patterns)

hookscustom-hooksdata-fetchingcache

4. Compound Components Pattern

advanced

Implement a Tabs component using the compound components pattern. The component should: 1. Allow flexible composition of Tab and TabPanel 2. Manage active tab state internally 3. Support keyboard navigation (arrow keys) 4. Be accessible (ARIA attributes) Example usage: <Tabs> <TabList> <Tab>First</Tab> <Tab>Second</Tab> </TabList> <TabPanel>First content</TabPanel> <TabPanel>Second content</TabPanel> </Tabs>

javascript
import { createContext, useContext, useState } from "react";

const TabsContext = createContext();

function Tabs({ children, defaultIndex = 0 }) {
  const [activeIndex, setActiveIndex] = useState(defaultIndex);
  
  const value = {
    activeIndex,
    setActiveIndex
  };
  
  return (
    <TabsContext.Provider value={value}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  );
}

function TabList({ children }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  
  const handleKeyDown = (e) => {
    const tabs = React.Children.toArray(children);
    const currentIndex = activeIndex;
    
    switch (e.key) {
      case "ArrowRight":
        e.preventDefault();
        setActiveIndex((currentIndex + 1) % tabs.length);
        break;
      case "ArrowLeft":
        e.preventDefault();
        setActiveIndex((currentIndex - 1 + tabs.length) % tabs.length);
        break;
      case "Home":
        e.preventDefault();
        setActiveIndex(0);
        break;
      case "End":
        e.preventDefault();
        setActiveIndex(tabs.length - 1);
        break;
    }
  };
  
  return (
    <div 
      role="tablist" 
      className="tab-list"
      onKeyDown={handleKeyDown}
    >
      {children}
    </div>
  );
}

function Tab({ children, index }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  const isActive = activeIndex === index;
  
  return (
    <button
      role="tab"
      aria-selected={isActive}
      className={`tab ${isActive ? "active" : ""}`}
      onClick={() => setActiveIndex(index)}
      tabIndex={isActive ? 0 : -1}
    >
      {children}
    </button>
  );
}

function TabPanel({ children, index }) {
  const { activeIndex } = useContext(TabsContext);
  const isActive = activeIndex === index;
  
  return (
    <div
      role="tabpanel"
      aria-hidden={!isActive}
      className={`tab-panel ${isActive ? "active" : ""}`}
      tabIndex={0}
    >
      {isActive && children}
    </div>
  );
}

// Usage
function App() {
  return (
    <Tabs defaultIndex={1}>
      <TabList>
        <Tab index={0}>Profile</Tab>
        <Tab index={1}>Messages</Tab>
        <Tab index={2}>Settings</Tab>
      </TabList>
      
      <TabPanel index={0}>
        <h2>Profile Content</h2>
        <p>Edit your profile here</p>
      </TabPanel>
      
      <TabPanel index={1}>
        <h2>Messages</h2>
        <p>Your messages will appear here</p>
      </TabPanel>
      
      <TabPanel index={2}>
        <h2>Settings</h2>
        <p>Configure your settings</p>
      </TabPanel>
    </Tabs>
  );
}

// Alternative: Clone children with props
function TabList({ children }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  
  return (
    <div role="tablist">
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, {
          isActive: activeIndex === index,
          onClick: () => setActiveIndex(index),
          index
        })
      )}
    </div>
  );
}

Answer: Compound components share state via Context Tabs manages active state, TabList/Tab/TabPanel consume Keyboard navigation with arrow keys ARIA attributes for accessibility

COMPOUND COMPONENTS PATTERN: Components that work together through implicit state sharing. BENEFITS: - Flexible API (users can reorder components) - Implicit state management - Clean separation of concerns - Good for complex UI components HOW IT WORKS: 1. Parent component (Tabs) provides Context 2. Child components (Tab, TabPanel) consume Context 3. State is shared implicitly 4. Users compose components as needed KEY IMPLEMENTATION DETAILS: - React Context for state sharing - React.Children.map + cloneElement (alternative) - ARIA attributes for accessibility - Keyboard navigation ALTERNATIVE APPROACHES: 1. Clone Element Pattern: Parent clones children with props 2. Render Props: More explicit but verbose 3. Hooks: useTabs() hook returns props USE CASES: - Tab components - Accordion/Expandable sections - Form fields with labels/errors - Data tables with sorting/filtering - Modal/dialog systems ACCESSIBILITY FEATURES: - role="tablist", role="tab", role="tabpanel" - aria-selected, aria-hidden - Keyboard navigation (arrows, Home, End) - Focus management PERFORMANCE CONSIDERATIONS: - Context triggers re-renders for all consumers - Memoize child components if needed - Consider using multiple contexts REAL-WORLD EXAMPLES: - Reach UI Tabs - Chakra UI components - Material-UI Tabs ASKED AT: Meta, Google, Microsoft (component design)

compound-componentscontextpatternsaccessibility

5. Render Props Pattern for Mouse Tracking

intermediate

Implement a MouseTracker component using the render props pattern. The component should: 1. Track mouse position 2. Accept a render prop function 3. Handle cleanup on unmount 4. Be reusable for different rendering needs Example usage: <MouseTracker> {({ x, y }) => ( <div> Mouse position: {x}, {y} </div> )} </MouseTracker>

javascript
function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  
  useEffect(() => {
    const handleMouseMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY });
    };
    
    window.addEventListener("mousemove", handleMouseMove);
    
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
    };
  }, []);
  
  return render(position);
}

// Usage example
function App() {
  return (
    <div style={{ height: "100vh" }}>
      <MouseTracker
        render={({ x, y }) => (
          <div>
            <h1>Mouse Position Tracker</h1>
            <p>
              X: {x}, Y: {y}
            </p>
            <div 
              style={{
                position: "absolute",
                left: x,
                top: y,
                width: "20px",
                height: "20px",
                backgroundColor: "red",
                borderRadius: "50%",
                transform: "translate(-50%, -50%)"
              }}
            />
          </div>
        )}
      />
    </div>
  );
}

// Alternative: Children as function (more common)
function MouseTracker({ children }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  
  useEffect(() => {
    const handleMouseMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY });
    };
    
    window.addEventListener("mousemove", handleMouseMove);
    
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
    };
  }, []);
  
  return children(position);
}

// Usage with children
function App() {
  return (
    <MouseTracker>
      {({ x, y }) => (
        <div>Mouse at: {x}, {y}</div>
      )}
    </MouseTracker>
  );
}

// Multiple render props example
function DataFetcher({ url, render, renderLoading, renderError }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [url]);
  
  if (loading && renderLoading) {
    return renderLoading();
  }
  
  if (error && renderError) {
    return renderError(error);
  }
  
  return render(data);
}

Answer: Render props pattern passes render function as prop MouseTracker tracks position, passes to render function Children-as-function variant more common Cleanup with removeEventListener

RENDER PROPS PATTERN: Component that accepts a function as prop and calls it with internal state. ADVANTAGES: - Highly flexible rendering - Reusable behavior logic - Easy to test - Explicit data flow DISADVANTAGES: - Can lead to nesting/callback hell - Slightly verbose - Performance concerns with inline functions COMMON PATTERNS: 1. Single render prop: <Component render={data => (...)} /> 2. Children as function: <Component> {data => (...)} </Component> 3. Multiple render props: <Component renderLoading={() => (...)} renderError={error => (...)} render={data => (...)} /> PERFORMANCE CONSIDERATIONS: - Inline functions create new references each render - Can cause unnecessary child re-renders - Use useCallback for stable references - Consider React.memo for child components MODERN ALTERNATIVES: - Custom Hooks (most common replacement) - Higher Order Components - Compound Components USE CASES: - Mouse/touch tracking - Data fetching - Form state management - Authentication - Theme/context providers REAL-WORLD EXAMPLES: - React Router Route component - Formik render props - Downshift component BEST PRACTICES: - Prefer children-as-function for single render prop - Provide meaningful prop names - Handle loading/error states - TypeScript: Generic types for render props ASKED AT: Meta, Airbnb, Stripe (legacy codebases)

render-propspatternscompositionreusability

6. Optimizing Context API for Performance

advanced

You have a ThemeContext that provides theme values (colors, spacing, etc.) to many components. Users report performance issues when theme changes cause unnecessary re-renders. How would you optimize? 1. What causes unnecessary re-renders? 2. How can you prevent them? 3. Provide optimized implementation.

javascript
// Problem: All consumers re-render when any context value changes
const ThemeContext = createContext({
  colors: { primary: "#000" },
  spacing: { small: "8px" }
});

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState({
    colors: { primary: "#007bff" },
    spacing: { small: "8px", medium: "16px" },
    mode: "light"
  });
  
  // This causes all consumers to re-render when any part changes
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Solution 1: Split contexts
const ThemeStateContext = createContext(null);
const ThemeUpdaterContext = createContext(null);

function OptimizedThemeProvider({ children }) {
  const [theme, setTheme] = useState({
    colors: { primary: "#007bff" },
    spacing: { small: "8px" },
    mode: "light"
  });
  
  // Memoize context values
  const themeState = useMemo(() => theme, [theme]);
  const themeUpdater = useMemo(() => setTheme, []);
  
  return (
    <ThemeStateContext.Provider value={themeState}>
      <ThemeUpdaterContext.Provider value={themeUpdater}>
        {children}
      </ThemeUpdaterContext.Provider>
    </ThemeStateContext.Provider>
  );
}

// Consumers only re-render when needed
function ThemeButton() {
  const theme = useContext(ThemeStateContext);
  // Only re-renders when theme changes
  return <button style={{ backgroundColor: theme.colors.primary }}>Click</button>;
}

function ThemeToggle() {
  const setTheme = useContext(ThemeUpdaterContext);
  // Doesn't re-render when theme changes, only needs updater
  return (
    <button onClick={() => setTheme(prev => ({
      ...prev,
      mode: prev.mode === "light" ? "dark" : "light"
    }))}>
      Toggle Theme
    </button>
  );
}

// Solution 2: Use selectors pattern
function useThemeSelector(selector) {
  const theme = useContext(ThemeStateContext);
  return useMemo(() => selector(theme), [theme, selector]);
}

// Component only re-renders when primary color changes
function PrimaryButton() {
  const primaryColor = useThemeSelector(theme => theme.colors.primary);
  return <button style={{ backgroundColor: primaryColor }}>Click</button>;
}

// Solution 3: Zustand/Recoil style atoms
const themeAtoms = {
  colors: atom({ primary: "#007bff" }),
  spacing: atom({ small: "8px" }),
  mode: atom("light")
};

// Components subscribe only to needed atoms

Answer: Split contexts: Separate state from updaters Memoize context values with useMemo Use selectors to subscribe to specific values Consider state management libraries for complex cases

CONTEXT API PERFORMANCE ISSUES: PROBLEMS: 1. All consumers re-render when any context value changes 2. Inline objects/functions create new references 3. Deeply nested consumers cause cascade re-renders 4. No fine-grained subscription capability OPTIMIZATION STRATEGIES: 1. SPLIT CONTEXTS: - Separate state from updaters - Separate frequently-changing from stable values - Example: UserContext → UserStateContext + UserDispatchContext 2. MEMOIZATION: - useMemo for context values - Stable function references with useCallback - Prevent unnecessary value changes 3. SELECTOR PATTERN: - Custom hooks that return specific values - Components subscribe to slices of state - Redux-style selectors for context 4. STATE NORMALIZATION: - Flatten nested state structures - Use IDs instead of nested objects - Easier to track changes 5. SKIP UNNECESSARY RE-RENDERS: - React.memo for consumer components - useMemo for expensive computations - ShouldComponentUpdate for class components ADVANCED PATTERNS: 1. Observer Pattern: Custom subscription system 2. Proxy-based tracking: Track accessed properties 3. Compiler optimizations: React Forget (future) WHEN TO USE CONTEXT VS STATE MANAGEMENT: - Context: Theme, Auth, Feature flags - Redux/Zustand: Complex app state, DevTools, Middleware - Recoil/Jotai: Derived state, Async state MEASUREMENT TOOLS: - React DevTools Profiler - Why did you re-render? library - Console logs with performance markers PRODUCTION EXAMPLE: - Next.js uses split contexts for router/theme - Chakra UI optimizes theme context - Formik uses selectors for form state ASKED AT: Meta, Google, Microsoft (performance optimization)

contextperformanceoptimizationre-renders

7. When to Use React.memo, useMemo, useCallback

intermediate

Explain the differences between React.memo, useMemo, and useCallback. When should each be used and what are the performance implications? Provide concrete examples where each optimization helps and where it might hurt performance.

javascript
// React.memo: Memoizes component
const ExpensiveComponent = React.memo(function ExpensiveComponent({ items, onSelect }) {
  console.log("ExpensiveComponent rendered");
  
  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => onSelect(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
});

// Custom comparison function (rarely needed)
const MemoizedWithCompare = React.memo(ExpensiveComponent, (prevProps, nextProps) => {
  // Return true if props are equal (no re-render needed)
  return prevProps.items.length === nextProps.items.length;
});

// useMemo: Memoizes expensive calculations
function UserList({ users, searchTerm }) {
  const filteredUsers = useMemo(() => {
    console.log("Filtering users...");
    return users.filter(user => 
      user.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [users, searchTerm]); // Recalculate when users or searchTerm changes
  
  return (
    <div>
      <div>Count: {filteredUsers.length}</div>
      <ExpensiveComponent items={filteredUsers} />
    </div>
  );
}

// useCallback: Memoizes function references
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [items, setItems] = useState([]);
  
  // Without useCallback: new function each render
  // const handleSelect = (id) => { console.log(id); };
  
  // With useCallback: stable function reference
  const handleSelect = useCallback((id) => {
    console.log("Selected:", id);
  }, []); // Empty deps: function never changes
  
  // With dependencies
  const handleSelectWithDeps = useCallback((id) => {
    console.log("Selected item", id, "from", items.length, "items");
  }, [items]); // Recreate when items changes
  
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>
        Rerender Parent ({count})
      </button>
      <ExpensiveComponent 
        items={items} 
        onSelect={handleSelect} // Stable reference prevents child re-renders
      />
    </div>
  );
}

// Example where memoization HURTS performance
function SimpleComponent({ text }) {
  // BAD: useMemo for simple concatenation
  // const message = useMemo(() => `Hello ${text}`, [text]);
  
  // GOOD: Direct computation
  const message = `Hello ${text}`;
  
  return <div>{message}</div>;
}

Answer: React.memo: Memoizes component re-renders useMemo: Memoizes expensive calculations useCallback: Memoizes function references Use when performance benefits outweigh overhead

PERFORMANCE OPTIMIZATION TRIO: REACT.MEMO: - Memoizes component output - Prevents re-renders when props don't change - Use for: Heavy components, Pure presentational components - Avoid for: Simple components, Components with frequently changing props - Custom comparison function for complex props USE MEMO: - Memoizes computed values - Use for: Expensive calculations, Filtering/sorting arrays, Object/array transformations - Avoid for: Simple calculations, Primitives, Small arrays - Rule of thumb: Computation takes >1ms or creates new references USE CALLBACK: - Memoizes function references - Use for: Prop functions passed to memoized children, Event handlers in effects dependencies - Avoid for: Functions that don't cause re-renders, Simple inline handlers - Note: Inline functions are cheap to create but cause re-renders PERFORMANCE TRADEOFFS: 1. MEMORY OVERHEAD: Memoization stores previous values 2. COMPUTATION OVERHEAD: Comparison functions run 3. COMPLEXITY: Harder to debug and reason about 4. PREMATURE OPTIMIZATION: Can make code slower WHEN TO OPTIMIZE: 1. Measured performance issues (Profiler shows bottlenecks) 2. Large lists or tables 3. Animation-heavy components 4. Real-time data updates MEASUREMENT TOOLS: - React DevTools Profiler - Chrome Performance tab - console.time() / console.timeEnd() - React.memo with why-did-you-render COMMON MISTAKES: 1. Memoizing everything (over-optimization) 2. Incorrect dependency arrays 3. Creating new objects in render anyway 4. Not measuring actual performance BEST PRACTICES: 1. Profile before optimizing 2. Start with React.memo at leaf components 3. Use useMemo for derived state 4. Use useCallback for prop functions 5. Test with production builds (dev mode is slower) ASKED AT: Meta, Google, Amazon (performance-focused roles)

react-memouseMemouseCallbackperformance

8. Error Boundaries Implementation

intermediate

Implement an ErrorBoundary component that: 1. Catches JavaScript errors in child components 2. Displays a fallback UI instead of crashing 3. Logs errors to an error reporting service 4. Provides a way to reset the error state Also implement a custom hook useErrorHandler for functional components.

javascript
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      hasError: false, 
      error: null,
      errorInfo: null 
    };
  }
  
  static getDerivedStateFromError(error) {
    // Update state so the next render shows the fallback UI
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    // Log the error to an error reporting service
    console.error("ErrorBoundary caught an error:", error, errorInfo);
    
    // Example: Send to error reporting service
    if (this.props.onError) {
      this.props.onError(error, errorInfo);
    }
    
    this.setState({ errorInfo });
  }
  
  handleReset = () => {
    this.setState({ 
      hasError: false, 
      error: null, 
      errorInfo: null 
    });
    
    if (this.props.onReset) {
      this.props.onReset();
    }
  };
  
  render() {
    if (this.state.hasError) {
      // Custom fallback UI
      if (this.props.fallback) {
        return this.props.fallback({
          error: this.state.error,
          errorInfo: this.state.errorInfo,
          resetError: this.handleReset
        });
      }
      
      // Default fallback
      return (
        <div className="error-boundary">
          <h2>Something went wrong</h2>
          <details>
            <summary>Error details</summary>
            <pre>{this.state.error?.toString()}</pre>
            <pre>{this.state.errorInfo?.componentStack}</pre>
          </details>
          <button onClick={this.handleReset}>Try again</button>
        </div>
      );
    }
    
    return this.props.children;
  }
}

// Usage examples
function App() {
  return (
    <ErrorBoundary
      onError={(error, errorInfo) => {
        // Send to Sentry/LogRocket
        console.error("App error:", error, errorInfo);
      }}
      fallback={({ error, resetError }) => (
        <div>
          <h1>Custom Error UI</h1>
          <p>{error.message}</p>
          <button onClick={resetError}>Retry</button>
        </div>
      )}
    >
      <BuggyComponent />
    </ErrorBoundary>
  );
}

// Custom hook for functional components
function useErrorHandler(givenError) {
  const [error, setError] = useState(null);
  
  useEffect(() => {
    if (givenError) {
      setError(givenError);
    }
  }, [givenError]);
  
  const handleError = useCallback((error) => {
    setError(error);
    
    // Log to service
    console.error("useErrorHandler caught:", error);
  }, []);
  
  const resetError = useCallback(() => {
    setError(null);
  }, []);
  
  return { error, handleError, resetError };
}

// Hook usage
function ComponentWithErrorHandling() {
  const { error, handleError, resetError } = useErrorHandler();
  
  const doSomethingRisky = useCallback(async () => {
    try {
      await riskyOperation();
    } catch (err) {
      handleError(err);
    }
  }, [handleError]);
  
  if (error) {
    return (
      <div>
        <p>Error: {error.message}</p>
        <button onClick={resetError}>Dismiss</button>
      </div>
    );
  }
  
  return <button onClick={doSomethingRisky}>Do Risky Thing</button>;
}

// Nested error boundaries for granular error handling
function App() {
  return (
    <ErrorBoundary fallback={<GlobalError />}>
      <Header />
      <ErrorBoundary fallback={<SidebarError />}>
        <Sidebar />
      </ErrorBoundary>
      <ErrorBoundary fallback={<ContentError />}>
        <MainContent />
      </ErrorBoundary>
    </ErrorBoundary>
  );
}

Answer: ErrorBoundary class component with getDerivedStateFromError and componentDidCatch Custom fallback UI and reset functionality useErrorHandler hook for functional components Nested boundaries for granular error recovery

ERROR BOUNDARIES PATTERN: React components that catch JavaScript errors in their child component tree. LIMITATIONS: - Only class components can be error boundaries - Catches errors during: render, lifecycle methods, constructors - Does NOT catch: Event handlers, Async code, SSR errors, Errors in error boundary itself KEY METHODS: 1. getDerivedStateFromError(): Update state for fallback UI 2. componentDidCatch(): Log errors, side effects PRODUCTION PATTERNS: 1. GRANULAR ERROR BOUNDARIES: - Wrap independent features - Prevent entire app from crashing - Example: Header, Sidebar, Main content separate 2. ERROR REPORTING: - Integrate with Sentry, LogRocket - Include user context - Track error frequency 3. RECOVERY STRATEGIES: - Retry button - Automatic retry with exponential backoff - Fallback to cached data 4. USER EXPERIENCE: - Friendly error messages - Contact support option - Save user work before error HOOKS WORKAROUND: Since hooks can't be error boundaries: - useErrorHandler for async operations - Try/catch in event handlers - Error state management REAL-WORLD IMPLEMENTATIONS: 1. Next.js: Built-in error boundaries 2. Create React App: Error overlay in development 3. React Router: Error boundary for route components TESTING STRATEGIES: - Mock component that throws - Test error recovery flow - Test logging integration BEST PRACTICES: - Use at least one top-level boundary - Add boundaries for independent features - Log to external service - Provide recovery options ASKED AT: Meta, Google, Netflix (production React)

error-boundarieserror-handlingpatternsreliability

9. Comparing State Management Solutions

advanced

Compare different state management solutions for React: 1. useState/useReducer 2. Context API 3. Redux (with Redux Toolkit) 4. Zustand 5. Recoil 6. MobX For each, explain: - When to use it - Pros and cons - Typical use case - Learning curve

javascript
// 1. useState/useReducer (Built-in)
function ComponentWithState() {
  const [count, setCount] = useState(0);
  
  // useReducer for complex state logic
  const [state, dispatch] = useReducer(reducer, initialState);
  
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

// 2. Context API
const UserContext = createContext();
function App() {
  const [user, setUser] = useState(null);
  
  return (
    <UserContext.Provider value={{ user, setUser }}>
      <ChildComponent />
    </UserContext.Provider>
  );
}

// 3. Redux Toolkit (Modern Redux)
import { configureStore, createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: 0,
  reducers: {
    increment: state => state + 1,
    decrement: state => state - 1
  }
});

const store = configureStore({
  reducer: {
    counter: counterSlice.reducer
  }
});

// 4. Zustand
import create from "zustand";

const useStore = create((set) => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
  reset: () => set({ count: 0 })
}));

function Component() {
  const { count, increment } = useStore();
  return <button onClick={increment}>{count}</button>;
}

// 5. Recoil
import { atom, selector, useRecoilState } from "recoil";

const countState = atom({
  key: "countState",
  default: 0
});

const doubledCount = selector({
  key: "doubledCount",
  get: ({ get }) => get(countState) * 2
});

function Component() {
  const [count, setCount] = useRecoilState(countState);
  const double = useRecoilValue(doubledCount);
  return <div>{count} * 2 = {double}</div>;
}

// 6. MobX
import { makeAutoObservable } from "mobx";
import { observer } from "mobx-react-lite";

class CounterStore {
  count = 0;
  
  constructor() {
    makeAutoObservable(this);
  }
  
  increment() {
    this.count++;
  }
}

const store = new CounterStore();

const Counter = observer(() => (
  <button onClick={() => store.increment()}>
    {store.count}
  </button>
));

Answer: useState/useReducer: Component state, simple cases Context: Theme/auth, medium apps, prop drilling Redux: Large apps, debugging, predictable updates Zustand: Simple global state, minimal boilerplate Recoil: Complex derived state, atom-based MobX: Observable pattern, OOP style

STATE MANAGEMENT DECISION TREE: 1. LOCAL STATE (useState/useReducer): - Single component state - Simple forms - UI state (toggles, modals) - Pros: Simple, no dependencies - Cons: Doesn't scale, prop drilling 2. CONTEXT API: - Theme/authentication - Small to medium apps - Avoiding prop drilling - Pros: Built-in, simple API - Cons: Performance issues, re-render all consumers 3. REDUX / REDUX TOOLKIT: - Large enterprise applications - Complex state with many reducers - Need for time-travel debugging - Pros: Predictable, middleware, DevTools - Cons: Boilerplate, steep learning curve 4. ZUSTAND: - Simpler alternative to Redux - Small to medium apps - Quick prototyping - Pros: Minimal boilerplate, hooks-based - Cons: Smaller ecosystem 5. RECOIL: - Complex derived/async state - Experimental features needed - Facebook projects - Pros: Atom-based, async support - Cons: Experimental, Facebook-specific 6. MOBX: - Observable pattern lovers - OOP background teams - Real-time updates - Pros: Simple mental model, automatic reactivity - Cons: Magic, less predictable SELECTION CRITERIA: 1. App Size: Small (Context) → Large (Redux) 2. Team Experience: Known tool vs learning new 3. Performance Needs: Fine-grained vs batched updates 4. Debugging Needs: Redux DevTools vs simple logging 5. Future Scaling: Will state needs grow? HYBRID APPROACH: Most apps use multiple solutions: - useState for local UI state - Context for theme/auth - Redux/Zustand for business logic MIGRATION PATH: Start with built-in, add libraries as needed: useState → Context → Zustand → Redux RECOMMENDATIONS 2024: - New projects: Zustand or Redux Toolkit - Existing Redux: Stay with Redux Toolkit - Simple apps: Context + useState - Complex derived state: Recoil/Jotai ASKED AT: Meta, Google, Amazon (architecture roles)

state-managementreduxcontextcomparison

10. React Server Components Implementation

advanced

Explain React Server Components (RSC) and demonstrate how to implement them. What problems do they solve? How do they differ from Server-Side Rendering (SSR)? Show example of: 1. Server Component fetching data 2. Client Component with interactivity 3. How they work together

javascript
// Server Component (app/page.js in Next.js 13+)
// This runs on the server, can directly access databases
import { db } from "@/lib/db";
import ClientComponent from "@/components/ClientComponent";

async function ServerComponent() {
  // Direct database access - no API route needed
  const products = await db.products.findMany({
    take: 10,
    orderBy: { createdAt: "desc" }
  });
  
  // No useState, useEffect, or event handlers here
  return (
    <div>
      <h1>Product List (Server Rendered)</h1>
      
      {/* Server component rendering */}
      <ul>
        {products.map(product => (
          <li key={product.id}>
            <h2>{product.name}</h2>
            <p>{product.description}</p>
            <span>${product.price}</span>
          </li>
        ))}
      </ul>
      
      {/* Client component for interactivity */}
      <ClientComponent initialProducts={products} />
    </div>
  );
}

// Client Component (components/ClientComponent.jsx)
"use client"; // Required directive

import { useState } from "react";

export default function ClientComponent({ initialProducts }) {
  const [products, setProducts] = useState(initialProducts);
  const [search, setSearch] = useState("");
  
  const filteredProducts = products.filter(p =>
    p.name.toLowerCase().includes(search.toLowerCase())
  );
  
  const addToCart = async (productId) => {
    // Client-side interaction
    await fetch("/api/cart", {
      method: "POST",
      body: JSON.stringify({ productId })
    });
    alert("Added to cart!");
  };
  
  return (
    <div>
      <h2>Interactive Product Search</h2>
      
      <input
        type="text"
        placeholder="Search products..."
        value={search}
        onChange={(e) => setSearch(e.target.value)}
      />
      
      <ul>
        {filteredProducts.map(product => (
          <li key={product.id}>
            <h3>{product.name}</h3>
            <button onClick={() => addToCart(product.id)}>
              Add to Cart
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

// Layout Component (app/layout.js)
// This is also a Server Component by default
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <header>
          <nav>
            {/* Navigation can be server component */}
            <a href="/">Home</a>
            <a href="/products">Products</a>
          </nav>
        </header>
        <main>{children}</main>
        <footer>
          {/* Server component fetching current year */}
          <p>© {new Date().getFullYear()} My Store</p>
        </footer>
      </body>
    </html>
  );
}

// Example of nested server/client components
// app/product/[id]/page.js
import ProductDetails from "@/components/ProductDetails";
import ProductReviews from "@/components/ProductReviews";
import AddToCartButton from "@/components/AddToCartButton";

async function ProductPage({ params }) {
  const product = await db.products.findUnique({
    where: { id: params.id },
    include: { reviews: true }
  });
  
  return (
    <div>
      {/* Server component fetching data */}
      <ProductDetails product={product} />
      
      {/* Client component for reviews with interactivity */}
      <ProductReviews reviews={product.reviews} />
      
      {/* Client component for cart actions */}
      <AddToCartButton productId={product.id} />
    </div>
  );
}

Answer: Server Components: Run on server, no client JS, direct data access Client Components: "use client" directive, interactivity, state RSC solves: Bundle size, data fetching waterfalls, SEO Different from SSR: Zero client JS for static parts

REACT SERVER COMPONENTS (RSC): New architecture where components can render on the server and stream to client. KEY CHARACTERISTICS: SERVER COMPONENTS: - Render exclusively on server - Zero bundle size impact - Direct database/API access - No interactivity (no event handlers) - No React state/lifecycle - Can import server-only modules CLIENT COMPONENTS: - Marked with "use client" directive - Render on client (after server) - Support interactivity, state, effects - Larger bundle size - Can't import server-only modules BENEFITS: 1. REDUCED BUNDLE SIZE: - Server components don't ship to client - Libraries stay on server (Moment.js, etc.) - Faster page loads 2. DIRECT DATA ACCESS: - No need for API routes - Database calls in components - Eliminates data fetching waterfalls 3. IMPROVED SEO: - Content rendered on server - Search engines see complete content - Better performance scores 4. STREAMING: - Send HTML in chunks - Show loading states progressively - Better perceived performance VS SERVER-SIDE RENDERING (SSR): - SSR: Entire page renders on server, ships as HTML, then hydrates - RSC: Components decide where to render, partial hydration - RSC: More granular, can stream - SSR: All-or-nothing approach IMPLEMENTATION PATTERNS: 1. COLOCATE DATA FETCHING: - Fetch data where it's used - No prop drilling of data - Type-safe with TypeScript 2. PROGRESSIVE ENHANCEMENT: - Start with server components - Add client components for interactivity - Fallbacks for non-JS users 3. COMPOSITION: - Server components can render client components - Client components can't render server components - Pass server data as props to client components LIMITATIONS: - Learning curve - Requires React 18+ and framework support - Debugging can be complex - Backend knowledge needed ADOPTION: - Next.js 13+ App Router (full support) - Experimental in other frameworks - Not available in plain React BEST PRACTICES: 1. Default to server components 2. Move interactivity to client components 3. Keep client components small 4. Use Suspense for loading states 5. Cache server component results ASKED AT: Meta, Vercel, Netflix (cutting-edge React)

server-componentsnextjsarchitectureperformance

11. React Suspense for Data Fetching

advanced

Implement data fetching with React Suspense. Create: 1. A wrapper that throws promise while loading 2. Error boundary for error handling 3. Suspense boundary with fallback 4. Cache mechanism for deduplication Example: <Suspense fallback={<Spinner />}> <UserProfile userId={123} /> </Suspense>

javascript
// 1. Create a cache for promises
const cache = new Map();

function fetchData(key, promiseFn) {
  if (!cache.has(key)) {
    cache.set(key, promiseFn());
  }
  return cache.get(key);
}

// 2. Create wrapper that throws promise
function useSuspenseFetch(key, promiseFn) {
  const data = fetchData(key, promiseFn);
  
  // Check if data is a promise (still loading)
  if (data && typeof data.then === "function") {
    throw data; // Suspense will catch this
  }
  
  // Check if data is an error
  if (data instanceof Error) {
    throw data; // Error boundary will catch this
  }
  
  return data;
}

// 3. User profile component using suspense
function UserProfile({ userId }) {
  const user = useSuspenseFetch(
    `user-${userId}`,
    () => fetch(`/api/users/${userId}`).then(res => res.json())
  );
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

// 4. App with Suspense boundaries
function App() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<div>Loading user...</div>}>
        <UserProfile userId={123} />
        <Suspense fallback={<div>Loading posts...</div>}>
          <UserPosts userId={123} />
        </Suspense>
      </Suspense>
    </ErrorBoundary>
  );
}

// 5. Alternative: React.lazy for code splitting
const LazyComponent = React.lazy(() => import("./HeavyComponent"));

function App() {
  return (
    <Suspense fallback={<div>Loading component...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

// 6. Concurrent features: useTransition
function SearchBox() {
  const [query, setQuery] = useState("");
  const [deferredQuery, setDeferredQuery] = useState("");
  const [isPending, startTransition] = useTransition();
  
  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value); // Immediate update
    
    startTransition(() => {
      setDeferredQuery(value); // Non-urgent update
    });
  };
  
  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending && <span>Updating...</span>}
      <SearchResults query={deferredQuery} />
    </div>
  );
}

// 7. useDeferredValue for deferred updates
function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  
  return (
    <div>
      <p>Showing results for: {deferredQuery}</p>
      {/* Expensive computation uses deferred value */}
    </div>
  );
}

Answer: Suspense throws promises for loading states Cache prevents duplicate requests Error boundaries handle errors useTransition/useDeferredValue for concurrent features

REACT SUSPENSE PATTERN: Declarative way to handle asynchronous operations in React. KEY CONCEPTS: 1. SUSPENSE BOUNDARY: - Catches thrown promises - Shows fallback while promise pending - Resumes rendering when promise resolves 2. ERROR BOUNDARY: - Catches thrown errors - Shows error UI - Separate from loading states 3. CACHE PATTERN: - Store promises in cache - Deduplicate requests - Enable immediate re-renders CONCURRENT FEATURES: 1. USE TRANSITION: - Mark updates as non-urgent - `isPending` shows loading state - Better user experience for slow updates 2. USE DEFERRED VALUE: - Defer updating value - Show stale content during updates - Smooth transitions 3. START TRANSITION: - Wrap state updates - Allow interruption of rendering - Improve responsiveness DATA FETCHING PATTERNS: 1. RENDER-AS-YOU-FETCH: - Start fetching early - Render as data arrives - Better than fetch-then-render 2. STREAMING SSR: - Send HTML in chunks - Suspense boundaries control streaming - Progressive loading PERFORMANCE BENEFITS: - No waterfall requests - Parallel data fetching - Immediate transitions - Non-blocking UI LIMITATIONS: - Experimental for data fetching - Requires specific patterns - Complex error handling BEST PRACTICES: 1. Place Suspense near loading content 2. Use multiple Suspense boundaries 3. Combine with Error Boundaries 4. Use for code splitting 5. Implement proper cache REAL-WORLD LIBRARIES: - React Query (TanStack Query) - SWR - Relay - Apollo Client ASKED AT: Meta, Vercel, Netflix (concurrent React)

suspenseconcurrentdata-fetchingperformance

12. React Portals for Modals and Tooltips

intermediate

Implement a modal system using React Portals. Requirements: 1. Create portal to render outside DOM hierarchy 2. Manage focus and keyboard navigation 3. Handle click outside to close 4. Support multiple modals with z-index 5. Accessible with ARIA attributes

javascript
// 1. Create portal component
import { useEffect } from "react";
import { createPortal } from "react-dom";

function Portal({ children, containerId = "portal-root" }) {
  const [container, setContainer] = useState(null);
  
  useEffect(() => {
    // Find or create container
    let portalContainer = document.getElementById(containerId);
    
    if (!portalContainer) {
      portalContainer = document.createElement("div");
      portalContainer.id = containerId;
      document.body.appendChild(portalContainer);
    }
    
    setContainer(portalContainer);
    
    return () => {
      // Don't remove container to avoid recreating
      // portalContainer.remove();
    };
  }, [containerId]);
  
  if (!container) return null;
  
  return createPortal(children, container);
}

// 2. Modal component using portal
function Modal({ isOpen, onClose, title, children }) {
  const modalRef = useRef();
  
  // Handle Escape key
  useEffect(() => {
    const handleEscape = (e) => {
      if (e.key === "Escape") {
        onClose();
      }
    };
    
    if (isOpen) {
      document.addEventListener("keydown", handleEscape);
      // Prevent body scroll
      document.body.style.overflow = "hidden";
      
      // Focus trap
      const focusableElements = modalRef.current?.querySelectorAll(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      
      if (focusableElements?.length > 0) {
        focusableElements[0].focus();
      }
    }
    
    return () => {
      document.removeEventListener("keydown", handleEscape);
      document.body.style.overflow = "auto";
    };
  }, [isOpen, onClose]);
  
  // Handle click outside
  const handleBackdropClick = (e) => {
    if (e.target === e.currentTarget) {
      onClose();
    }
  };
  
  if (!isOpen) return null;
  
  return (
    <Portal>
      <div 
        className="modal-backdrop"
        onClick={handleBackdropClick}
        role="presentation"
      >
        <div 
          ref={modalRef}
          className="modal"
          role="dialog"
          aria-modal="true"
          aria-labelledby="modal-title"
        >
          <div className="modal-header">
            <h2 id="modal-title">{title}</h2>
            <button 
              onClick={onClose}
              aria-label="Close modal"
              className="close-button"
            >
              ×
            </button>
          </div>
          <div className="modal-content">
            {children}
          </div>
        </div>
      </div>
    </Portal>
  );
}

// 3. Usage
function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);
  
  return (
    <div>
      <button onClick={() => setIsModalOpen(true)}>
        Open Modal
      </button>
      
      <Modal
        isOpen={isModalOpen}
        onClose={() => setIsModalOpen(false)}
        title="Example Modal"
      >
        <p>Modal content goes here.</p>
        <button onClick={() => alert("Action!")}>
          Action Button
        </button>
      </Modal>
    </div>
  );
}

// 4. Tooltip using portal
function Tooltip({ children, content }) {
  const [isVisible, setIsVisible] = useState(false);
  const [position, setPosition] = useState({ x: 0, y: 0 });
  const triggerRef = useRef();
  
  const showTooltip = () => {
    const rect = triggerRef.current.getBoundingClientRect();
    setPosition({
      x: rect.left + rect.width / 2,
      y: rect.top
    });
    setIsVisible(true);
  };
  
  return (
    <>
      <span
        ref={triggerRef}
        onMouseEnter={showTooltip}
        onMouseLeave={() => setIsVisible(false)}
        onFocus={showTooltip}
        onBlur={() => setIsVisible(false)}
        aria-describedby="tooltip-content"
      >
        {children}
      </span>
      
      {isVisible && (
        <Portal>
          <div
            className="tooltip"
            style={{
              position: "fixed",
              left: position.x,
              top: position.y,
              transform: "translate(-50%, -100%)"
            }}
            role="tooltip"
            id="tooltip-content"
          >
            {content}
          </div>
        </Portal>
      )}
    </>
  );
}

Answer: Portals render outside DOM hierarchy Modal with focus trap and keyboard navigation Click outside to close Tooltip with positioning

REACT PORTALS PATTERN: Render children into a DOM node outside parent hierarchy. USE CASES: 1. Modals/Dialogs 2. Tooltips/Popovers 3. Dropdown menus 4. Notifications/Toasts 5. Loading overlays BENEFITS: - Escape CSS overflow:hidden - Proper z-index stacking - Clean DOM structure - Better accessibility IMPLEMENTATION DETAILS: 1. PORTAL CREATION: - Use ReactDOM.createPortal() - Create container element - Append to document.body - Cleanup on unmount 2. MODAL FEATURES: - Focus trap (first element gets focus) - Escape key to close - Click outside to close - Prevent body scroll - ARIA attributes 3. TOOLTIP FEATURES: - Position calculation - Mouse enter/leave - Focus/blur events - Arrow positioning ACCESSIBILITY REQUIREMENTS: - role="dialog" for modals - aria-modal="true" - aria-labelledby/aria-describedby - Keyboard navigation (Tab, Escape) - Screen reader announcements PERFORMANCE CONSIDERATIONS: - Portal container reuse - Event listener cleanup - Avoid unnecessary re-renders - Debounce positioning calculations MULTIPLE PORTALS: - Z-index management - Stacking context - Click-through prevention - Focus order between portals REAL-WORLD EXAMPLES: 1. Material-UI Modal 2. Chakra UI Modal 3. React Bootstrap Modal 4. Reach UI Dialog BEST PRACTICES: 1. Always cleanup event listeners 2. Handle SSR (document not available) 3. Support server-side rendering 4. Test with screen readers 5. Support reduced motion ALTERNATIVES: 1. CSS-only modals (limited) 2. iframe (heavy) 3. Third-party libraries ASKED AT: Meta, Google, Microsoft (UI component design)

portalsmodalsaccessibilityui-patterns

13. ForwardRef Pattern for Component Libraries

intermediate

Implement a TextInput component that: 1. Forwards ref to underlying input element 2. Supports custom styling 3. Exposes focus() and blur() methods 4. Works with form libraries 5. Has proper TypeScript types

javascript
// 1. Basic forwardRef implementation
import { forwardRef, useImperativeHandle, useRef } from "react";

const TextInput = forwardRef(function TextInput(props, ref) {
  const inputRef = useRef();
  
  // Expose methods to parent via ref
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    blur: () => {
      inputRef.current.blur();
    },
    getValue: () => {
      return inputRef.current.value;
    },
    setValue: (value) => {
      inputRef.current.value = value;
    },
    // Expose the DOM element
    element: inputRef.current
  }));
  
  return (
    <input
      ref={inputRef}
      {...props}
      className={`text-input ${props.className || ""}`}
    />
  );
});

// 2. Usage
function Form() {
  const inputRef = useRef();
  
  const handleFocus = () => {
    inputRef.current?.focus();
  };
  
  const handleGetValue = () => {
    console.log(inputRef.current?.getValue());
  };
  
  return (
    <div>
      <TextInput
        ref={inputRef}
        placeholder="Enter text"
        onChange={(e) => console.log(e.target.value)}
      />
      <button onClick={handleFocus}>Focus Input</button>
      <button onClick={handleGetValue}>Get Value</button>
    </div>
  );
}

// 3. With TypeScript
type TextInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  error?: boolean;
  variant?: "outlined" | "filled";
};

type TextInputHandle = {
  focus: () => void;
  blur: () => void;
  getValue: () => string;
  setValue: (value: string) => void;
  element: HTMLInputElement | null;
};

const TextInput = forwardRef<TextInputHandle, TextInputProps>(
  function TextInput(props, ref) {
    const inputRef = useRef<HTMLInputElement>(null);
    
    useImperativeHandle(ref, () => ({
      focus: () => inputRef.current?.focus(),
      blur: () => inputRef.current?.blur(),
      getValue: () => inputRef.current?.value || "",
      setValue: (value: string) => {
        if (inputRef.current) {
          inputRef.current.value = value;
        }
      },
      element: inputRef.current
    }));
    
    const className = `text-input ${props.variant || "outlined"} ${
      props.error ? "error" : ""
    } ${props.className || ""}`;
    
    return (
      <input
        ref={inputRef}
        {...props}
        className={className}
      />
    );
  }
);

// 4. Higher Order Component with forwardRef
function withLogging(WrappedComponent) {
  return forwardRef(function WithLogging(props, ref) {
    const componentRef = useRef();
    
    // Merge refs
    const setRef = useCallback((node) => {
      componentRef.current = node;
      
      // Handle ref prop
      if (typeof ref === "function") {
        ref(node);
      } else if (ref) {
        ref.current = node;
      }
    }, [ref]);
    
    useEffect(() => {
      console.log("Component mounted:", componentRef.current);
      return () => {
        console.log("Component unmounted");
      };
    }, []);
    
    return (
      <WrappedComponent
        {...props}
        ref={setRef}
      />
    );
  });
}

const TextInputWithLogging = withLogging(TextInput);

// 5. Form integration example
function FormWithRef() {
  const formRef = useRef();
  
  const handleSubmit = (e) => {
    e.preventDefault();
    
    // Access all inputs via ref
    const inputs = formRef.current.querySelectorAll("input");
    const values = Array.from(inputs).map(input => input.value);
    console.log(values);
  };
  
  return (
    <form ref={formRef} onSubmit={handleSubmit}>
      <TextInput name="username" required />
      <TextInput name="email" type="email" />
      <button type="submit">Submit</button>
    </form>
  );
}

Answer: forwardRef passes ref to child component useImperativeHandle exposes custom methods TypeScript provides type safety Works with form libraries

FORWARDREF PATTERN: Pass ref through component to underlying DOM element. USE CASES: 1. Component libraries 2. Form inputs 3. Focus management 4. Animation libraries 5. Third-party integration KEY APIS: 1. FORWARDREF: - Wraps component - Receives ref as second parameter - Passes ref to child element 2. USE IMPERATIVE HANDLE: - Customize ref value - Expose specific methods - Hide implementation details 3. REF MERGING: - Multiple ref consumers - Callback ref pattern - Ref forwarding through HOCs BENEFITS: 1. DOM ACCESS: Parent can call focus(), blur() 2. INTEGRATION: Works with form libraries 3. ENCAPSULATION: Hide implementation details 4. TYPE SAFETY: TypeScript support COMMON PATTERNS: 1. FORM INPUT COMPONENTS: - Expose value methods - Support validation - Integrate with Formik/React Hook Form 2. FOCUS MANAGEMENT: - Programmatic focus - Focus trap - Auto-focus 3. ANIMATION LIBRARIES: - Expose animate() method - Control animations - Integration with Framer Motion PERFORMANCE CONSIDERATIONS: - Avoid inline ref functions - Memoize ref callbacks - Use useCallback for stable refs - Batch ref updates TYPESCRIPT TIPS: 1. Generic forwardRef types 2. Ref type parameter 3. Props type parameter 4. Optional ref methods REAL-WORLD EXAMPLES: 1. Material-UI TextField 2. Chakra UI Input 3. React Select 4. React Datepicker ANTI-PATTERNS: 1. Over-exposing internal methods 2. Breaking component encapsulation 3. Creating ref spaghetti 4. Ignoring accessibility BEST PRACTICES: 1. Only expose necessary methods 2. Document ref API 3. Support both callback and object refs 4. Test ref functionality ASKED AT: Meta, Google, Stripe (component library design)

forwardrefrefstypescriptcomponent-libraries

14. Lazy Loading and Dynamic Imports

intermediate

Implement code splitting in a React application: 1. Route-based code splitting 2. Component-based lazy loading 3. Prefetching strategies 4. Loading states and error boundaries 5. Bundle analysis and optimization

javascript
// 1. Basic React.lazy usage
import { lazy, Suspense } from "react";

const HeavyComponent = lazy(() => import("./HeavyComponent"));
const AnotherComponent = lazy(() => import("./AnotherComponent"));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

// 2. Route-based splitting
import { BrowserRouter, Routes, Route } from "react-router-dom";

const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const Contact = lazy(() => import("./pages/Contact"));

function RouterApp() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Loading page...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

// 3. Named exports with lazy
const UserProfile = lazy(() =>
  import("./UserProfile").then(module => ({
    default: module.UserProfile
  }))
);

// 4. Preloading strategy
function usePreload(moduleImport) {
  return useCallback(() => {
    moduleImport();
  }, [moduleImport]);
}

function Navigation() {
  const preloadAbout = usePreload(() => import("./pages/About"));
  
  return (
    <nav>
      <Link 
        to="/about"
        onMouseEnter={preloadAbout}
        onFocus={preloadAbout}
      >
        About
      </Link>
    </nav>
  );
}

// 5. Bundle analysis with webpack magic comments
const Analytics = lazy(() =>
  import(
    /* webpackChunkName: "analytics" */
    /* webpackPrefetch: true */
    /* webpackPreload: true */
    "./Analytics"
  )
);

// 6. Error boundary for lazy loading
class LazyLoadingErrorBoundary extends React.Component {
  state = { hasError: false, error: null };
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  retry = () => {
    this.setState({ hasError: false, error: null });
    // Force remount of lazy component
    this.forceUpdate();
  };
  
  render() {
    if (this.state.hasError) {
      return (
        <div>
          <p>Failed to load component</p>
          <button onClick={this.retry}>Retry</button>
        </div>
      );
    }
    
    return this.props.children;
  }
}

// 7. Dynamic import with conditions
function DynamicComponent({ componentName }) {
  const Component = lazy(() => {
    if (componentName === "Chart") {
      return import("./ChartComponent");
    } else if (componentName === "Table") {
      return import("./TableComponent");
    }
    return import("./DefaultComponent");
  });
  
  return (
    <Suspense fallback={<div>Loading {componentName}...</div>}>
      <Component />
    </Suspense>
  );
}

// 8. Bundle analysis tool
function BundleAnalyzer() {
  useEffect(() => {
    if (process.env.NODE_ENV === "development") {
      import("webpack-bundle-analyzer").then(({ BundleAnalyzerPlugin }) => {
        // Configure analyzer
      });
    }
  }, []);
  
  return null;
}

Answer: React.lazy for component code splitting Suspense for loading states Route-based splitting with React Router Prefetching for better UX

CODE SPLITTING PATTERNS: Split bundle into smaller chunks loaded on demand. BENEFITS: 1. FASTER INITIAL LOAD: Smaller initial bundle 2. BETTER PERFORMANCE: Load only needed code 3. CACHE EFFICIENCY: Independent chunk caching 4. BANDWIDTH SAVINGS: Avoid unused code download SPLITTING STRATEGIES: 1. ROUTE-BASED: - Split by page/route - Natural user journey boundaries - Easy to implement 2. COMPONENT-BASED: - Split heavy components - Modal/dialog content - Below-the-fold content 3. VENDOR SPLITTING: - Separate third-party libraries - Stable chunk hashes - Better caching 4. DYNAMIC IMPORTS: - Load on user interaction - Conditional loading - Feature flags PERFORMANCE OPTIMIZATIONS: 1. PREFETCHING: - Load during idle time - Mouse hover/focus events - webpackPrefetch comment 2. PRELOADING: - High priority loading - Critical resources - webpackPreload comment 3. BUNDLE ANALYSIS: - webpack-bundle-analyzer - Source map exploration - Duplicate detection IMPLEMENTATION DETAILS: 1. REACT.LAZY: - Works with default exports - Requires Suspense boundary - Error boundary for failures 2. SUSPENSE: - Shows fallback during loading - Can be nested - Supports concurrent features 3. WEBPACK MAGIC COMMENTS: - webpackChunkName: Custom chunk names - webpackPrefetch: Idle time loading - webpackPreload: High priority loading ERROR HANDLING: 1. Network failures 2. Module not found 3. Loading timeouts 4. Retry mechanisms MEASUREMENT METRICS: 1. First Contentful Paint 2. Time to Interactive 3. Bundle size reduction 4. Cache hit ratio BEST PRACTICES: 1. Split at route boundaries 2. Use meaningful chunk names 3. Implement loading states 4. Add error boundaries 5. Monitor bundle sizes TOOLS: 1. Webpack Bundle Analyzer 2. Source Map Explorer 3. Lighthouse 4. Webpack performance hints ASKED AT: Meta, Google, Netflix (performance optimization)

lazy-loadingcode-splittingperformancewebpack

15. Container/Presentational Components

intermediate

Implement the Container/Presentational pattern: 1. Container handles data/logic 2. Presentational handles UI rendering 3. Clear separation of concerns 4. Testable components 5. Reusable presentational components

javascript
// 1. Presentational Component (Dumb/Stateless)
function UserListPresentation({ users, isLoading, error, onUserClick }) {
  if (error) {
    return <div className="error">Error: {error.message}</div>;
  }
  
  if (isLoading) {
    return <div className="loading">Loading users...</div>;
  }
  
  return (
    <ul className="user-list">
      {users.map(user => (
        <li 
          key={user.id}
          className="user-item"
          onClick={() => onUserClick(user.id)}
        >
          <img src={user.avatar} alt={user.name} />
          <div>
            <h3>{user.name}</h3>
            <p>{user.email}</p>
          </div>
        </li>
      ))}
    </ul>
  );
}

// 2. Container Component (Smart/Stateful)
function UserListContainer() {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const response = await fetch("/api/users");
        const data = await response.json();
        setUsers(data);
      } catch (err) {
        setError(err);
      } finally {
        setIsLoading(false);
      }
    };
    
    fetchUsers();
  }, []);
  
  const handleUserClick = useCallback((userId) => {
    console.log("User clicked:", userId);
    // Navigate or show details
  }, []);
  
  return (
    <UserListPresentation
      users={users}
      isLoading={isLoading}
      error={error}
      onUserClick={handleUserClick}
    />
  );
}

// 3. Hooks-based Container (Modern approach)
function useUsers() {
  const [state, setState] = useState({
    users: [],
    isLoading: true,
    error: null
  });
  
  useEffect(() => {
    fetchUsers();
  }, []);
  
  const fetchUsers = async () => {
    try {
      const response = await fetch("/api/users");
      const users = await response.json();
      setState({ users, isLoading: false, error: null });
    } catch (error) {
      setState({ users: [], isLoading: false, error });
    }
  };
  
  const updateUser = useCallback((userId, updates) => {
    setState(prev => ({
      ...prev,
      users: prev.users.map(user =>
        user.id === userId ? { ...user, ...updates } : user
      )
    }));
  }, []);
  
  return {
    ...state,
    fetchUsers,
    updateUser
  };
}

// Container using custom hook
function UserListContainerWithHook() {
  const { users, isLoading, error, updateUser } = useUsers();
  
  return (
    <UserListPresentation
      users={users}
      isLoading={isLoading}
      error={error}
      onUserClick={(userId) => {
        updateUser(userId, { selected: true });
      }}
    />
  );
}

// 4. Higher Order Component Container
function withUsers(WrappedComponent) {
  return function WithUsers(props) {
    const usersData = useUsers();
    
    return (
      <WrappedComponent
        {...props}
        {...usersData}
      />
    );
  };
}

// Enhanced component
const UserListWithUsers = withUsers(UserListPresentation);

// 5. Render Props Container
function UsersContainer({ children }) {
  const usersData = useUsers();
  
  return children(usersData);
}

// Usage
function App() {
  return (
    <UsersContainer>
      {({ users, isLoading, error }) => (
        <UserListPresentation
          users={users}
          isLoading={isLoading}
          error={error}
        />
      )}
    </UsersContainer>
  );
}

// 6. Testing presentational component
// Easy to test with mock props
test("UserListPresentation renders users", () => {
  const mockUsers = [
    { id: 1, name: "John", email: "john@example.com", avatar: "" }
  ];
  
  render(
    <UserListPresentation
      users={mockUsers}
      isLoading={false}
      error={null}
      onUserClick={jest.fn()}
    />
  );
  
  expect(screen.getByText("John")).toBeInTheDocument();
});

Answer: Container handles data/logic, Presentational handles UI Clear separation of concerns Custom hooks for reusable logic Easy testing of presentational components

CONTAINER/PRESENTATIONAL PATTERN: Separation of data/logic from UI rendering. BENEFITS: 1. SEPARATION OF CONCERNS: Clear responsibilities 2. REUSABILITY: Presentational components reusable 3. TESTABILITY: Easy to test in isolation 4. MAINTAINABILITY: Changes isolated to one layer MODERN EVOLUTION: 1. HOOKS: Replace container components 2. CUSTOM HOOKS: Extract logic 3. RENDER PROPS: Flexible composition 4. HOC: Reuse logic across components PRESENTATIONAL COMPONENTS: - Receive data via props - No internal state (usually) - No side effects - Pure rendering - Styled components CONTAINER COMPONENTS: - Manage state - Handle side effects - Business logic - Data fetching - Pass data to presentational IMPLEMENTATION PATTERNS: 1. CLASSIC: - Container class component - Presentational functional component 2. HOOKS-BASED: - Custom hook for logic - Functional container - Same presentational component 3. HOC: - Higher Order Component wrapper - Inject props - Reusable across components 4. RENDER PROPS: - Container provides data - Children function renders - Maximum flexibility TESTING STRATEGIES: 1. PRESENTATIONAL: - Test with mock props - Snapshot testing - User interaction tests 2. CONTAINER: - Mock API calls - State transitions - Side effect testing PERFORMANCE: - Presentational components can be memoized - Container re-renders on data changes - Optimize with React.memo REAL-WORLD USAGE: 1. FORM CONTAINERS: Handle form state 2. DATA FETCHING: API integration 3. AUTHENTICATION: User state management 4. THEMING: Theme propagation BEST PRACTICES: 1. Keep presentational components pure 2. Use TypeScript for prop types 3. Document component contracts 4. Test both layers independently ALTERNATIVE PATTERNS: 1. HEADLESS UI: Logic without styling 2. COMPOUND COMPONENTS: Shared state 3. PROVIDER PATTERN: Context-based ASKED AT: Meta, Google, Amazon (architecture design)

containerpresentationalseparation-of-concernsarchitecture

16. Dependency Injection for Testing

advanced

Implement dependency injection in React for: 1. Mocking API clients in tests 2. Switching implementations (real vs mock) 3. Service layer abstraction 4. Testing components in isolation

javascript
// 1. Service interface
class ApiService {
  async getUsers() {
    throw new Error("Not implemented");
  }
  
  async createUser(userData) {
    throw new Error("Not implemented");
  }
}

// 2. Real implementation
class RealApiService extends ApiService {
  async getUsers() {
    const response = await fetch("/api/users");
    return response.json();
  }
  
  async createUser(userData) {
    const response = await fetch("/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(userData)
    });
    return response.json();
  }
}

// 3. Mock implementation for testing
class MockApiService extends ApiService {
  constructor() {
    super();
    this.users = [
      { id: 1, name: "Test User", email: "test@example.com" }
    ];
  }
  
  async getUsers() {
    return this.users;
  }
  
  async createUser(userData) {
    const newUser = { id: Date.now(), ...userData };
    this.users.push(newUser);
    return newUser;
  }
}

// 4. Context for dependency injection
const ApiServiceContext = createContext(new RealApiService());

function ApiServiceProvider({ children, service }) {
  return (
    <ApiServiceContext.Provider value={service}>
      {children}
    </ApiServiceContext.Provider>
  );
}

// 5. Hook to use service
function useApiService() {
  return useContext(ApiServiceContext);
}

// 6. Component using injected service
function UserList() {
  const [users, setUsers] = useState([]);
  const apiService = useApiService();
  
  useEffect(() => {
    apiService.getUsers().then(setUsers);
  }, [apiService]);
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

// 7. App with real service
function App() {
  return (
    <ApiServiceProvider service={new RealApiService()}>
      <UserList />
    </ApiServiceProvider>
  );
}

// 8. Testing with mock service
describe("UserList", () => {
  it("renders users from mock service", async () => {
    const mockService = new MockApiService();
    
    render(
      <ApiServiceProvider service={mockService}>
        <UserList />
      </ApiServiceProvider>
    );
    
    // Wait for users to load
    await screen.findByText("Test User");
    
    expect(screen.getByText("Test User")).toBeInTheDocument();
  });
});

// 9. Factory pattern for service creation
function createApiService(config) {
  if (config.useMock) {
    return new MockApiService();
  }
  
  if (config.env === "test") {
    return new MockApiService();
  }
  
  return new RealApiService();
}

// 10. Parameter injection alternative
function UserList({ apiService = new RealApiService() }) {
  const [users, setUsers] = useState([]);
  
  useEffect(() => {
    apiService.getUsers().then(setUsers);
  }, [apiService]);
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

// 11. Higher Order Component injection
function withApiService(WrappedComponent) {
  return function WithApiService(props) {
    const apiService = useApiService();
    
    return (
      <WrappedComponent
        {...props}
        apiService={apiService}
      />
    );
  };
}

const UserListWithService = withApiService(UserList);

Answer: Dependency injection via Context API Service interfaces with real/mock implementations Testing with mocked services Factory pattern for environment-based creation

DEPENDENCY INJECTION IN REACT: Provide dependencies from outside rather than hardcoding. BENEFITS: 1. TESTABILITY: Easy mocking 2. FLEXIBILITY: Switch implementations 3. MAINTAINABILITY: Decoupled code 4. CONFIGURATION: Environment-based setups IMPLEMENTATION PATTERNS: 1. CONTEXT API: - Service provider component - Context for service access - Default implementation 2. PROP INJECTION: - Pass service as prop - Default parameter values - Explicit dependencies 3. HIGHER ORDER COMPONENTS: - Wrap with service injection - Reuse across components - TypeScript support 4. CUSTOM HOOKS: - useService() hook - Service access abstraction - Testing hooks SERVICE DESIGN: 1. INTERFACE/ABSTRACT CLASS: - Define contract - Multiple implementations - TypeScript interfaces 2. REAL IMPLEMENTATION: - Production code - API integration - Error handling 3. MOCK IMPLEMENTATION: - Test data - Simulated responses - Controlled behavior TESTING STRATEGIES: 1. UNIT TESTS: - Mock services - Isolated components - Fast execution 2. INTEGRATION TESTS: - Real services - End-to-end flows - Environment setup 3. E2E TESTS: - Production setup - User scenarios - Browser testing CONFIGURATION PATTERNS: 1. ENVIRONMENT VARIABLES: - NODE_ENV based - Feature flags - Service URLs 2. FACTORY PATTERN: - Create based on config - Singleton services - Cached instances 3. LAZY LOADING: - Dynamic imports - Code splitting - Bundle optimization PERFORMANCE CONSIDERATIONS: - Service instance creation - Context re-renders - Memoization of services - Singleton pattern REAL-WORLD USE CASES: 1. API CLIENT: Axios vs Fetch 2. AUTHENTICATION: Real vs mock auth 3. ANALYTICS: Production vs dev 4. STORAGE: localStorage vs IndexedDB BEST PRACTICES: 1. Define clear interfaces 2. Use TypeScript 3. Default to real implementation 4. Easy testing setup 5. Document service contracts ASKED AT: Meta, Google, Microsoft (testing architecture)

dependency-injectiontestingarchitectureservices

17. Factory Pattern for Dynamic Components

advanced

Implement a component factory that: 1. Creates components based on configuration 2. Handles dynamic component types 3. Supports plugins/extensions 4. Type-safe with TypeScript 5. Configurable via JSON

javascript
// 1. Component registry
const componentRegistry = {};

function registerComponent(type, component) {
  componentRegistry[type] = component;
}

function getComponent(type) {
  const component = componentRegistry[type];
  
  if (!component) {
    throw new Error(`Component type "${type}" not registered`);
  }
  
  return component;
}

// 2. Component factory
function ComponentFactory({ type, props, children }) {
  const Component = getComponent(type);
  
  return (
    <Component {...props}>
      {children}
    </Component>
  );
}

// 3. Example components
const Button = ({ label, onClick, variant = "primary" }) => (
  <button 
    className={`btn btn-${variant}`}
    onClick={onClick}
  >
    {label}
  </button>
);

const Input = ({ label, value, onChange, type = "text" }) => (
  <div className="form-group">
    <label>{label}</label>
    <input
      type={type}
      value={value}
      onChange={onChange}
      className="form-control"
    />
  </div>
);

const Card = ({ title, children }) => (
  <div className="card">
    {title && <div className="card-header">{title}</div>}
    <div className="card-body">{children}</div>
  </div>
);

// 4. Register components
registerComponent("button", Button);
registerComponent("input", Input);
registerComponent("card", Card);

// 5. Dynamic form from configuration
const formConfig = [
  { type: "card", props: { title: "User Registration" },
    children: [
      { 
        type: "input", 
        props: { 
          label: "Name",
          name: "name",
          required: true 
        } 
      },
      { 
        type: "input", 
        props: { 
          label: "Email",
          name: "email",
          type: "email"
        } 
      },
      { 
        type: "button", 
        props: { 
          label: "Submit",
          variant: "primary",
          onClick: () => console.log("Submitted")
        } 
      }
    ]
  }
];

function DynamicForm({ config }) {
  const renderComponent = (item, index) => {
    const { type, props, children } = item;
    
    return (
      <ComponentFactory
        key={index}
        type={type}
        props={props}
      >
        {children && children.map(renderComponent)}
      </ComponentFactory>
    );
  };
  
  return config.map(renderComponent);
}

// 6. TypeScript support
type ComponentType = "button" | "input" | "card" | string;

interface ComponentConfig {
  type: ComponentType;
  props: Record<string, any>;
  children?: ComponentConfig[];
}

interface ComponentFactoryProps {
  type: ComponentType;
  props: Record<string, any>;
  children?: React.ReactNode;
}

// 7. Plugin system
function registerPlugin(plugin) {
  plugin.components.forEach(({ type, component }) => {
    registerComponent(type, component);
  });
}

const chartPlugin = {
  components: [
    { type: "lineChart", component: LineChart },
    { type: "barChart", component: BarChart }
  ]
};

registerPlugin(chartPlugin);

// 8. Dynamic component loader
async function loadComponent(type) {
  // Dynamic import based on type
  switch (type) {
    case "richTextEditor":
      return import("./RichTextEditor").then(m => m.default);
    case "dataGrid":
      return import("./DataGrid").then(m => m.default);
    default:
      return getComponent(type);
  }
}

function AsyncComponentFactory({ type, props }) {
  const [Component, setComponent] = useState(null);
  
  useEffect(() => {
    loadComponent(type).then(setComponent);
  }, [type]);
  
  if (!Component) {
    return <div>Loading {type}...</div>;
  }
  
  return <Component {...props} />;
}

// 9. Usage
function App() {
  return (
    <div>
      <DynamicForm config={formConfig} />
      
      {/* Direct factory usage */}
      <ComponentFactory
        type="card"
        props={{ title: "Manual Card" }}
      >
        <p>This content is manually passed.</p>
        <ComponentFactory
          type="button"
          props={{ label: "Click me", onClick: () => alert("Clicked") }}
        />
      </ComponentFactory>
    </div>
  );
}

Answer: Component registry maps types to components Factory creates components based on type Dynamic forms from JSON configuration Plugin system for extensibility

FACTORY PATTERN FOR COMPONENTS: Create objects without specifying exact class. USE CASES: 1. CMS/BUILDER SYSTEMS: Drag-and-drop builders 2. FORM GENERATORS: Dynamic forms from JSON 3. PLUGIN ARCHITECTURES: Extensible systems 4. CONFIGURATION-DRIVEN UIS: JSON-driven interfaces IMPLEMENTATION PATTERNS: 1. REGISTRY PATTERN: - Central component registry - Type-to-component mapping - Runtime registration 2. FACTORY COMPONENT: - Looks up component by type - Passes props and children - Error handling for missing types 3. CONFIGURATION DRIVEN: - JSON configuration - Nested component trees - Dynamic rendering 4. PLUGIN SYSTEM: - External component registration - Lazy loading - Version compatibility ADVANCED FEATURES: 1. ASYNC LOADING: - Dynamic imports - Code splitting - Loading states 2. VALIDATION: - Prop validation - Required fields - Type checking 3. THEMING: - Style injection - Theme propagation - Component variants 4. STATE MANAGEMENT: - Form state - Validation state - Submission handling PERFORMANCE OPTIMIZATIONS: - Memoize factory components - Lazy load heavy components - Cache component instances - Virtualize lists TYPE SAFETY: 1. TypeScript generics 2. Component type unions 3. Prop type validation 4. Configuration schema validation REAL-WORLD EXAMPLES: 1. FORM.IO: Dynamic form builder 2. STORYBOOK: Component explorer 3. RETOOL: Internal tool builder 4. SANITY: Content studio SECURITY CONSIDERATIONS: 1. Sanitize configuration 2. Validate component types 3. Limit accessible components 4. Sandbox dynamic code BEST PRACTICES: 1. Default error component 2. Component versioning 3. Documentation generation 4. Test configuration files ASKED AT: Meta, Google, Microsoft (platform engineering)

factory-patterndynamic-componentspluginsconfiguration

18. Provider Pattern with Multiple Contexts

intermediate

Implement a multi-context provider pattern: 1. Theme provider with light/dark mode 2. Auth provider with user state 3. Notification provider with toasts 4. Combined provider for clean app setup 5. Custom hooks for each context

javascript
// 1. Theme Context
const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");
  
  const toggleTheme = useCallback(() => {
    setTheme(prev => prev === "light" ? "dark" : "light");
  }, []);
  
  const value = useMemo(() => ({
    theme,
    toggleTheme,
    isDark: theme === "dark"
  }), [theme, toggleTheme]);
  
  return (
    <ThemeContext.Provider value={value}>
      <div className={`theme-${theme}`}>
        {children}
      </div>
    </ThemeContext.Provider>
  );
}

function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within ThemeProvider");
  }
  return context;
}

// 2. Auth Context
const AuthContext = createContext();

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    // Check stored auth
    const storedUser = localStorage.getItem("user");
    if (storedUser) {
      setUser(JSON.parse(storedUser));
    }
    setLoading(false);
  }, []);
  
  const login = useCallback(async (credentials) => {
    // API call
    const response = await fetch("/api/login", {
      method: "POST",
      body: JSON.stringify(credentials)
    });
    
    const userData = await response.json();
    setUser(userData);
    localStorage.setItem("user", JSON.stringify(userData));
  }, []);
  
  const logout = useCallback(() => {
    setUser(null);
    localStorage.removeItem("user");
  }, []);
  
  const value = useMemo(() => ({
    user,
    loading,
    login,
    logout,
    isAuthenticated: !!user
  }), [user, loading, login, logout]);
  
  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;
}

// 3. Notification Context
const NotificationContext = createContext();

function NotificationProvider({ children }) {
  const [notifications, setNotifications] = useState([]);
  
  const addNotification = useCallback((notification) => {
    const id = Date.now();
    const newNotification = { id, ...notification };
    
    setNotifications(prev => [...prev, newNotification]);
    
    // Auto remove after 5 seconds
    setTimeout(() => {
      removeNotification(id);
    }, 5000);
  }, []);
  
  const removeNotification = useCallback((id) => {
    setNotifications(prev => prev.filter(n => n.id !== id));
  }, []);
  
  const value = useMemo(() => ({
    notifications,
    addNotification,
    removeNotification,
    success: (message) => addNotification({ type: "success", message }),
    error: (message) => addNotification({ type: "error", message }),
    info: (message) => addNotification({ type: "info", message })
  }), [notifications, addNotification, removeNotification]);
  
  return (
    <NotificationContext.Provider value={value}>
      {children}
      <NotificationList />
    </NotificationContext.Provider>
  );
}

function NotificationList() {
  const { notifications, removeNotification } = useNotification();
  
  return (
    <div className="notifications">
      {notifications.map(notification => (
        <div 
          key={notification.id}
          className={`notification notification-${notification.type}`}
        >
          {notification.message}
          <button onClick={() => removeNotification(notification.id)}>
            ×
          </button>
        </div>
      ))}
    </div>
  );
}

function useNotification() {
  const context = useContext(NotificationContext);
  if (!context) {
    throw new Error("useNotification must be used within NotificationProvider");
  }
  return context;
}

// 4. Combined Provider
function AppProvider({ children }) {
  return (
    <ThemeProvider>
      <AuthProvider>
        <NotificationProvider>
          {children}
        </NotificationProvider>
      </AuthProvider>
    </ThemeProvider>
  );
}

// 5. Usage in components
function UserProfile() {
  const { user, logout } = useAuth();
  const { theme, toggleTheme } = useTheme();
  const { success } = useNotification();
  
  const handleLogout = () => {
    logout();
    success("Logged out successfully");
  };
  
  return (
    <div className="profile">
      <h2>Welcome, {user.name}</h2>
      <button onClick={handleLogout}>Logout</button>
      <button onClick={toggleTheme}>
        Switch to {theme === "light" ? "Dark" : "Light"} Mode
      </button>
    </div>
  );
}

// 6. App setup
function App() {
  return (
    <AppProvider>
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/profile" element={<UserProfile />} />
        </Routes>
      </Router>
    </AppProvider>
  );
}

// 7. TypeScript version
type Theme = "light" | "dark";

interface ThemeContextValue {
  theme: Theme;
  toggleTheme: () => void;
  isDark: boolean;
}

const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);

// 8. Performance optimized provider
function OptimizedProvider({ children }) {
  // Split contexts to avoid unnecessary re-renders
  return (
    <ThemeProvider>
      <AuthStateProvider>
        <AuthActionsProvider>
          <NotificationProvider>
            {children}
          </NotificationProvider>
        </AuthActionsProvider>
      </AuthStateProvider>
    </ThemeProvider>
  );
}

Answer: Multiple providers for theme, auth, notifications Combined AppProvider for clean setup Custom hooks for each context TypeScript support for type safety

PROVIDER PATTERN: Component that provides data/functionality to descendants via Context. BENEFITS: 1. GLOBAL STATE: Accessible anywhere in tree 2. PROP DRILLING SOLUTION: Avoid passing through many levels 3. REUSABLE LOGIC: Encapsulate complex logic 4. TESTABILITY: Easy to mock providers COMMON PROVIDERS: 1. THEME PROVIDER: - Color schemes - Typography - Spacing 2. AUTH PROVIDER: - User authentication - Login/logout - Protected routes 3. NOTIFICATION PROVIDER: - Toast messages - Alerts - Progress indicators 4. DATA PROVIDER: - API caching - Data fetching - State management IMPLEMENTATION PATTERNS: 1. SINGLE PROVIDER: - One context - Simple state - Small apps 2. MULTIPLE PROVIDERS: - Separate concerns - Nested providers - Combined provider component 3. SPLIT PROVIDERS: - State vs actions - Optimize re-renders - Fine-grained updates PERFORMANCE OPTIMIZATIONS: 1. MEMOIZATION: - useMemo for context value - useCallback for functions - Prevent unnecessary re-renders 2. CONTEXT SPLITTING: - Separate state from updaters - Static vs dynamic values - Reduce consumer re-renders 3. SELECTOR PATTERN: - Custom hooks with selectors - Subscribe to specific values - Avoid full context re-renders TESTING STRATEGIES: 1. PROVIDER MOCKING: - Mock context values - Test components in isolation - Provider test wrappers 2. INTEGRATION TESTS: - Real providers - User flows - State transitions 3. E2E TESTS: - Full app with providers - Authentication flows - Theme switching BEST PRACTICES: 1. Always provide default values 2. Create custom hooks for consumption 3. Split large providers 4. Document provider contracts 5. Use TypeScript REAL-WORLD EXAMPLES: 1. REACT ROUTER: Router provider 2. REDUX: Provider component 3. APOLLO CLIENT: ApolloProvider 4. MATERIAL-UI: ThemeProvider ASKED AT: Meta, Google, Amazon (application architecture)

provider-patterncontextarchitecturestate-management

19. Composing Custom Hooks

intermediate

Create and compose custom hooks: 1. useLocalStorage hook 2. useFetch hook 3. useDebounce hook 4. Compose them for complex logic 5. TypeScript support

javascript
// 1. useLocalStorage hook
function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });
  
  const setValue = useCallback((value) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  }, [key, storedValue]);
  
  const removeValue = useCallback(() => {
    try {
      setStoredValue(initialValue);
      window.localStorage.removeItem(key);
    } catch (error) {
      console.error(error);
    }
  }, [key, initialValue]);
  
  return [storedValue, setValue, removeValue];
}

// 2. useFetch hook (simplified)
function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const controller = new AbortController();
    
    const fetchData = async () => {
      try {
        const response = await fetch(url, {
          ...options,
          signal: controller.signal
        });
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const result = await response.json();
        setData(result);
      } catch (err) {
        if (err.name !== "AbortError") {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
    
    return () => controller.abort();
  }, [url, JSON.stringify(options)]);
  
  return { data, loading, error };
}

// 3. useDebounce hook
function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);
  
  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    
    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);
  
  return debouncedValue;
}

// 4. Composed hook: useLocalStorageFetch
function useLocalStorageFetch(key, url) {
  // Get cached data from localStorage
  const [cachedData, setCachedData, removeCachedData] = useLocalStorage(key, null);
  
  // Fetch fresh data
  const { data: freshData, loading, error } = useFetch(url);
  
  // Update cache when fresh data arrives
  useEffect(() => {
    if (freshData) {
      setCachedData(freshData);
    }
  }, [freshData, setCachedData]);
  
  // Determine which data to show
  const data = freshData || cachedData;
  
  // Clear cache
  const clearCache = useCallback(() => {
    removeCachedData();
  }, [removeCachedData]);
  
  return {
    data,
    loading,
    error,
    clearCache,
    isCached: !!cachedData && !freshData
  };
}

// 5. Composed hook: useDebouncedSearch
function useDebouncedSearch(initialQuery = "", delay = 300) {
  const [query, setQuery] = useState(initialQuery);
  const debouncedQuery = useDebounce(query, delay);
  
  const { data: results, loading, error } = useFetch(
    debouncedQuery ? `/api/search?q=${debouncedQuery}` : null
  );
  
  return {
    query,
    setQuery,
    debouncedQuery,
    results,
    loading,
    error
  };
}

// 6. Composed hook: useForm with validation and localStorage
function useForm(initialState, options = {}) {
  const { validate, persistKey } = options;
  
  // Get persisted form data or use initial
  const [persistedData, setPersistedData, clearPersistedData] = useLocalStorage(
    persistKey,
    initialState
  );
  
  const [formData, setFormData] = useState(persistedData);
  const [errors, setErrors] = useState({});
  const [touched, setTouched] = useState({});
  
  // Update localStorage on change
  useEffect(() => {
    if (persistKey) {
      setPersistedData(formData);
    }
  }, [formData, persistKey, setPersistedData]);
  
  const handleChange = useCallback((field, value) => {
    setFormData(prev => ({
      ...prev,
      [field]: value
    }));
    
    // Clear error when user starts typing
    setErrors(prev => ({
      ...prev,
      [field]: undefined
    }));
  }, []);
  
  const handleBlur = useCallback((field) => {
    setTouched(prev => ({
      ...prev,
      [field]: true
    }));
    
    // Validate on blur
    if (validate) {
      const fieldErrors = validate(field, formData[field], formData);
      if (fieldErrors) {
        setErrors(prev => ({
          ...prev,
          [field]: fieldErrors
        }));
      }
    }
  }, [validate, formData]);
  
  const resetForm = useCallback(() => {
    setFormData(initialState);
    setErrors({});
    setTouched({});
    if (persistKey) {
      clearPersistedData();
    }
  }, [initialState, persistKey, clearPersistedData]);
  
  return {
    formData,
    handleChange,
    handleBlur,
    errors,
    touched,
    resetForm,
    setFormData
  };
}

// 7. Usage example
function SearchComponent() {
  const {
    query,
    setQuery,
    results,
    loading,
    error
  } = useDebouncedSearch();
  
  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />
      
      {loading && <div>Loading...</div>}
      {error && <div>Error: {error.message}</div>}
      
      <ul>
        {results?.map(result => (
          <li key={result.id}>{result.name}</li>
        ))}
      </ul>
    </div>
  );
}

// 8. TypeScript generic hooks
type UseLocalStorageReturn<T> = [T, (value: T | ((val: T) => T)) => void, () => void];

function useLocalStorage<T>(key: string, initialValue: T): UseLocalStorageReturn<T> {
  // Implementation with types
}

Answer: Custom hooks for localStorage, fetching, debouncing Composed hooks combine multiple hooks TypeScript generics for type safety Reusable logic extraction

HOOKS COMPOSITION PATTERN: Combine multiple hooks to create complex behavior. BENEFITS: 1. REUSABILITY: Logic shared across components 2. COMPOSABILITY: Combine simple hooks 3. TESTABILITY: Isolated logic testing 4. MAINTAINABILITY: Centralized logic COMMON HOOKS TO CREATE: 1. STATE MANAGEMENT: - useLocalStorage - useSessionStorage - usePrevious 2. DATA FETCHING: - useFetch - useQuery (GraphQL) - useMutation 3. UI/UX: - useDebounce - useThrottle - useMediaQuery - useClickOutside 4. FORMS: - useForm - useField - useValidation 5. PERFORMANCE: - useMemoCompare - useWhyDidYouUpdate - useRenderCount COMPOSITION PATTERNS: 1. SEQUENTIAL COMPOSITION: - Hook results used in next hook - Example: useDebounce → useFetch 2. PARALLEL COMPOSITION: - Multiple independent hooks - Combine results at the end 3. NESTED COMPOSITION: - Hooks within custom hooks - Shared state between hooks PERFORMANCE CONSIDERATIONS: - Memoize hook results - Avoid unnecessary re-renders - Cleanup side effects - Dependency array optimization TESTING STRATEGIES: 1. UNIT TESTS: - Test hooks in isolation - Mock dependencies - Test return values 2. INTEGRATION TESTS: - Test composed hooks - Real dependencies - Interaction testing 3. E2E TESTS: - Full user flows - Hook integration BEST PRACTICES: 1. Name hooks with "use" prefix 2. Return consistent interface 3. Handle errors gracefully 4. Provide cleanup functions 5. Document hook API TYPE SAFETY: 1. TypeScript generics 2. Proper return types 3. Input validation 4. Error types REAL-WORLD LIBRARIES: 1. REACT USE: Collection of hooks 2. USE-HOOKS: Common patterns 3. SWR/REACT QUERY: Data fetching 4. FORMIK/REACT HOOK FORM: Form handling ASKED AT: Meta, Google, Netflix (custom hooks)

custom-hookscompositiontypescriptreusability

20. State Machines for Complex UI Logic

advanced

Implement a fetch machine with XState: 1. Define states: idle, loading, success, error 2. Transitions between states 3. Side effects (fetching) 4. React integration 5. TypeScript support

javascript
import { createMachine, assign } from "xstate";
import { useMachine } from "@xstate/react";

// 1. Define the machine
const fetchMachine = createMachine({
  id: "fetch",
  initial: "idle",
  context: {
    data: null,
    error: null
  },
  states: {
    idle: {
      on: {
        FETCH: "loading"
      }
    },
    loading: {
      invoke: {
        src: "fetchData",
        onDone: {
          target: "success",
          actions: assign({
            data: (_, event) => event.data
          })
        },
        onError: {
          target: "error",
          actions: assign({
            error: (_, event) => event.data
          })
        }
      },
      on: {
        CANCEL: "idle"
      }
    },
    success: {
      on: {
        REFETCH: "loading",
        RESET: {
          target: "idle",
          actions: assign({
            data: null,
            error: null
          })
        }
      }
    },
    error: {
      on: {
        RETRY: "loading",
        RESET: {
          target: "idle",
          actions: assign({
            data: null,
            error: null
          })
        }
      }
    }
  }
});

// 2. Services (side effects)
const services = {
  fetchData: async (context, event) => {
    const response = await fetch(event.url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  }
};

// 3. React component using the machine
function FetchComponent({ url }) {
  const [state, send] = useMachine(fetchMachine, {
    services
  });
  
  const { data, error } = state.context;
  
  const handleFetch = () => {
    send({ type: "FETCH", url });
  };
  
  const handleCancel = () => {
    send({ type: "CANCEL" });
  };
  
  const handleRetry = () => {
    send({ type: "RETRY", url });
  };
  
  const handleReset = () => {
    send({ type: "RESET" });
  };
  
  return (
    <div>
      <div>Current state: {state.value}</div>
      
      {state.matches("idle") && (
        <button onClick={handleFetch}>
          Fetch Data
        </button>
      )}
      
      {state.matches("loading") && (
        <div>
          <div>Loading...</div>
          <button onClick={handleCancel}>Cancel</button>
        </div>
      )}
      
      {state.matches("success") && (
        <div>
          <h3>Data loaded successfully</h3>
          <pre>{JSON.stringify(data, null, 2)}</pre>
          <button onClick={handleFetch}>Refetch</button>
          <button onClick={handleReset}>Reset</button>
        </div>
      )}
      
      {state.matches("error") && (
        <div>
          <h3>Error: {error?.message}</h3>
          <button onClick={handleRetry}>Retry</button>
          <button onClick={handleReset}>Reset</button>
        </div>
      )}
    </div>
  );
}

// 4. TypeScript version
interface FetchContext {
  data: any;
  error: Error | null;
}

type FetchEvent =
  | { type: "FETCH"; url: string }
  | { type: "CANCEL" }
  | { type: "RETRY"; url: string }
  | { type: "RESET" }
  | { type: "REFETCH"; url: string };

type FetchState =
  | { value: "idle"; context: FetchContext }
  | { value: "loading"; context: FetchContext }
  | { value: "success"; context: FetchContext & { data: any } }
  | { value: "error"; context: FetchContext & { error: Error } };

// 5. Form machine example
const formMachine = createMachine({
  id: "form",
  initial: "editing",
  context: {
    values: {},
    errors: {},
    touched: {}
  },
  states: {
    editing: {
      on: {
        CHANGE: {
          actions: assign({
            values: (context, event) => ({
              ...context.values,
              [event.field]: event.value
            })
          })
        },
        BLUR: {
          actions: assign({
            touched: (context, event) => ({
              ...context.touched,
              [event.field]: true
            })
          })
        },
        SUBMIT: {
          target: "validating",
          cond: "hasChanges"
        }
      }
    },
    validating: {
      invoke: {
        src: "validateForm",
        onDone: [
          {
            target: "submitting",
            cond: (_, event) => event.data.isValid
          },
          {
            target: "editing",
            actions: assign({
              errors: (_, event) => event.data.errors
            })
          }
        ]
      }
    },
    submitting: {
      invoke: {
        src: "submitForm",
        onDone: "success",
        onError: {
          target: "editing",
          actions: assign({
            errors: (_, event) => ({ submit: event.data.message })
          })
        }
      }
    },
    success: {
      type: "final"
    }
  }
});

// 6. Parallel states
const multiStepFormMachine = createMachine({
  id: "multiStepForm",
  type: "parallel",
  states: {
    step1: {
      initial: "idle",
      states: {
        idle: { on: { NEXT: "completed" } },
        completed: { type: "final" }
      }
    },
    step2: {
      initial: "idle",
      states: {
        idle: { on: { NEXT: "completed" } },
        completed: { type: "final" }
      }
    },
    step3: {
      initial: "idle",
      states: {
        idle: { 
          on: { 
            NEXT: "completed",
            SKIP: "skipped" 
          } 
        },
        completed: { type: "final" },
        skipped: { type: "final" }
      }
    }
  },
  on: {
    RESET: {
      target: [".step1.idle", ".step2.idle", ".step3.idle"]
    }
  }
});

Answer: XState machines define states and transitions React integration with useMachine TypeScript for type safety Parallel states for complex workflows

STATE MACHINES PATTERN: Explicitly model application states and transitions. BENEFITS: 1. PREDICTABLE: All states defined 2. VISUALIZABLE: Can generate statecharts 3. TESTABLE: Easy to test transitions 4. MAINTAINABLE: Clear state logic KEY CONCEPTS: 1. STATES: - Finite set of states - Nested/parallel states - Initial/final states 2. TRANSITIONS: - Events trigger transitions - Guards for conditions - Actions on transitions 3. CONTEXT: - Extended state - Data associated with machine - Can be updated 4. SERVICES: - Side effects - Promises/observables - Callbacks REACT INTEGRATION: 1. USE MACHINE: - Hook to use machine - Returns [state, send] - Service management 2. ACTORS: - Spawn child machines - Communication between machines - Complex workflows USE CASES: 1. DATA FETCHING: - Loading states - Error handling - Retry logic 2. FORMS: - Validation states - Submission flow - Multi-step forms 3. UI COMPONENTS: - Modal/dialog states - Accordion/tabs - Wizard flows 4. AUTHENTICATION: - Login/logout flow - Session management - Permission states PERFORMANCE: - Machines are lightweight - Minimal re-renders - Efficient state updates - Memory efficient TOOLING: 1. XSTATE VISUALIZER: Visualize machines 2. XSTATE INSPECT: Debug machines 3. TYPE GENERATION: TypeScript support 4. TESTING: Built-in test utilities ALTERNATIVES: 1. USE REDUCER: Simple state machines 2. ZUSTAND: Simple state management 3. REDUX SAGA: Complex side effects 4. MOBX STATE TREE: Tree-based state BEST PRACTICES: 1. Start with simple machines 2. Use TypeScript 3. Keep machines focused 4. Test all transitions 5. Visualize complex machines ASKED AT: Meta, Microsoft, Netflix (complex UI logic)

state-machinesxstatefinite-state-machinescomplex-ui

21. Optimistic Updates Pattern

advanced

Implement optimistic updates for a todo list: 1. Show immediate UI update 2. Send async request 3. Rollback on error 4. Retry failed updates 5. Handle race conditions

javascript
// 1. Custom hook for optimistic updates
function useOptimisticUpdate(initialData, updateFn, options = {}) {
  const [data, setData] = useState(initialData);
  const [optimisticUpdates, setOptimisticUpdates] = useState(new Map());
  const [errors, setErrors] = useState(new Map());
  
  const applyUpdate = useCallback(async (id, update) => {
    // Generate optimistic ID
    const optimisticId = `opt_${Date.now()}`;
    
    // 1. Apply optimistic update immediately
    setData(prev => {
      const newData = [...prev];
      const index = newData.findIndex(item => item.id === id);
      
      if (index !== -1) {
        newData[index] = {
          ...newData[index],
          ...update,
          _optimisticId: optimisticId,
          _isOptimistic: true
        };
      }
      
      return newData;
    });
    
    // Store optimistic update
    setOptimisticUpdates(prev => 
      new Map(prev).set(optimisticId, { id, update })
    );
    
    try {
      // 2. Send actual API request
      const result = await updateFn(id, update);
      
      // 3. Replace optimistic item with real data
      setData(prev => {
        const newData = [...prev];
        const index = newData.findIndex(
          item => item._optimisticId === optimisticId
        );
        
        if (index !== -1) {
          newData[index] = {
            ...result,
            _optimisticId: undefined,
            _isOptimistic: false
          };
        }
        
        return newData;
      });
      
      // Remove from optimistic updates
      setOptimisticUpdates(prev => {
        const next = new Map(prev);
        next.delete(optimisticId);
        return next;
      });
      
      return { success: true, data: result };
      
    } catch (error) {
      // 4. Rollback on error
      setData(prev => {
        const newData = [...prev];
        const index = newData.findIndex(
          item => item._optimisticId === optimisticId
        );
        
        if (index !== -1) {
          // Remove the optimistic item
          newData.splice(index, 1);
        }
        
        return newData;
      });
      
      // Store error
      setErrors(prev => 
        new Map(prev).set(optimisticId, { error, id, update })
      );
      
      // Remove from optimistic updates
      setOptimisticUpdates(prev => {
        const next = new Map(prev);
        next.delete(optimisticId);
        return next;
      });
      
      return { success: false, error };
    }
  }, [updateFn]);
  
  const retryUpdate = useCallback(async (optimisticId) => {
    const failedUpdate = errors.get(optimisticId);
    if (!failedUpdate) return;
    
    // Remove from errors
    setErrors(prev => {
      const next = new Map(prev);
      next.delete(optimisticId);
      return next;
    });
    
    // Retry the update
    return applyUpdate(failedUpdate.id, failedUpdate.update);
  }, [errors, applyUpdate]);
  
  const retryAll = useCallback(async () => {
    const results = [];
    for (const [optimisticId] of errors) {
      const result = await retryUpdate(optimisticId);
      results.push(result);
    }
    return results;
  }, [errors, retryUpdate]);
  
  return {
    data,
    applyUpdate,
    retryUpdate,
    retryAll,
    optimisticCount: optimisticUpdates.size,
    errorCount: errors.size,
    hasErrors: errors.size > 0
  };
}

// 2. Todo list component using optimistic updates
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: "Learn React", completed: false }
  ]);
  
  const api = {
    updateTodo: async (id, updates) => {
      const response = await fetch(`/api/todos/${id}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(updates)
      });
      return response.json();
    }
  };
  
  const {
    data: optimisticTodos,
    applyUpdate,
    retryAll,
    hasErrors
  } = useOptimisticUpdate(todos, api.updateTodo);
  
  const toggleTodo = async (id) => {
    const todo = optimisticTodos.find(t => t.id === id);
    if (!todo) return;
    
    await applyUpdate(id, { completed: !todo.completed });
  };
  
  const addTodo = async (text) => {
    const optimisticId = `new_${Date.now()}`;
    
    // Optimistic add
    setTodos(prev => [
      ...prev,
      { id: optimisticId, text, completed: false, _isOptimistic: true }
    ]);
    
    try {
      // Real API call
      const response = await fetch("/api/todos", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text, completed: false })
      });
      
      const newTodo = await response.json();
      
      // Replace optimistic with real
      setTodos(prev => 
        prev.map(todo => 
          todo.id === optimisticId ? newTodo : todo
        )
      );
      
    } catch (error) {
      // Rollback
      setTodos(prev => 
        prev.filter(todo => todo.id !== optimisticId)
      );
      
      alert("Failed to add todo");
    }
  };
  
  return (
    <div>
      {hasErrors && (
        <div className="error-banner">
          Some updates failed. 
          <button onClick={retryAll}>Retry All</button>
        </div>
      )}
      
      <ul>
        {optimisticTodos.map(todo => (
          <li 
            key={todo.id}
            className={`todo-item ${todo._isOptimistic ? "optimistic" : ""}`}
          >
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
              disabled={todo._isOptimistic}
            />
            <span style={{
              textDecoration: todo.completed ? "line-through" : "none",
              opacity: todo._isOptimistic ? 0.6 : 1
            }}>
              {todo.text}
            </span>
            {todo._isOptimistic && (
              <span className="optimistic-badge">Saving...</span>
            )}
          </li>
        ))}
      </ul>
    </div>
  );
}

// 3. Optimistic delete
function useOptimisticDelete(deleteFn) {
  const [deletingIds, setDeletingIds] = useState(new Set());
  
  const deleteItem = useCallback(async (id) => {
    // Add to deleting set
    setDeletingIds(prev => new Set(prev).add(id));
    
    try {
      await deleteFn(id);
      // Success - remove from set
      setDeletingIds(prev => {
        const next = new Set(prev);
        next.delete(id);
        return next;
      });
    } catch (error) {
      // Error - remove from set and show error
      setDeletingIds(prev => {
        const next = new Set(prev);
        next.delete(id);
        return next;
      });
      throw error;
    }
  }, [deleteFn]);
  
  return { deleteItem, deletingIds };
}

Answer: Optimistic updates show immediate UI changes Rollback on API failure Retry mechanism for failed updates Visual feedback for optimistic state

OPTIMISTIC UPDATES PATTERN: Update UI immediately, then sync with server, rollback on failure. BENEFITS: 1. BETTER UX: Immediate feedback 2. PERCEIVED PERFORMANCE: Feels faster 3. SMOOTH INTERACTIONS: No waiting indicators for every action IMPLEMENTATION PATTERNS: 1. OPTIMISTIC CREATE: - Add temporary item with unique ID - Send create request - Replace with real data on success - Remove on failure 2. OPTIMISTIC UPDATE: - Apply changes locally - Mark item as optimistic - Send update request - Update with server response - Rollback on error 3. OPTIMISTIC DELETE: - Remove from UI immediately - Send delete request - Permanently remove on success - Restore on failure CHALLENGES: 1. RACE CONDITIONS: - Multiple updates to same item - Use optimistic IDs - Sequential updates 2. CONFLICT RESOLUTION: - Server vs client state - Last write wins - Conflict detection 3. ERROR HANDLING: - Rollback strategies - Retry mechanisms - User notifications 4. STATE CONSISTENCY: - Offline support - Sync conflicts - Data integrity PERFORMANCE CONSIDERATIONS: - Minimal UI updates - Efficient rollback - Memory management for failed updates - Batch optimistic changes REAL-WORLD EXAMPLES: 1. SOCIAL MEDIA: Likes, comments 2. TODO APPS: Check/uncheck 3. SHOPPING CARTS: Add/remove items 4. MESSAGING: Send messages BEST PRACTICES: 1. Visual feedback for optimistic state 2. Always implement rollback 3. Provide retry options 4. Handle network failures gracefully 5. Test offline scenarios TOOLS & LIBRARIES: 1. React Query: Optimistic updates 2. SWR: Mutation with optimistic UI 3. Apollo Client: Optimistic responses 4. Redux: Middleware for optimistic updates ASKED AT: Meta, Twitter, Instagram (UX-heavy apps)

optimistic-updatesuxerror-handlingperformance

22. Infinite Scroll with Virtualization

advanced

Implement virtualized infinite scroll: 1. Load data in chunks 2. Virtualize DOM elements 3. Handle scroll position 4. Lazy load images 5. Accessibility support

javascript
// 1. Virtualized list component
function VirtualizedList({
  items,
  itemHeight,
  containerHeight,
  renderItem,
  loading,
  onLoadMore
}) {
  const containerRef = useRef();
  const [scrollTop, setScrollTop] = useState(0);
  
  // Calculate visible items
  const totalItems = items.length;
  const visibleCount = Math.ceil(containerHeight / itemHeight);
  
  // Find start and end indices
  const startIndex = Math.max(
    0,
    Math.floor(scrollTop / itemHeight) - 5 // Buffer
  );
  
  const endIndex = Math.min(
    totalItems - 1,
    startIndex + visibleCount + 10 // Buffer
  );
  
  // Handle scroll
  const handleScroll = useCallback((e) => {
    const scrollTop = e.target.scrollTop;
    setScrollTop(scrollTop);
    
    // Check if we need to load more
    const scrollBottom = scrollTop + containerHeight;
    const totalHeight = totalItems * itemHeight;
    
    if (scrollBottom >= totalHeight - 500 && !loading) {
      onLoadMore();
    }
  }, [containerHeight, totalItems, itemHeight, loading, onLoadMore]);
  
  // Calculate container style
  const containerStyle = {
    height: containerHeight,
    overflowY: "auto",
    position: "relative"
  };
  
  // Calculate inner container height
  const innerHeight = totalItems * itemHeight;
  
  // Calculate transform for visible items
  const transform = `translateY(${startIndex * itemHeight}px)`;
  
  return (
    <div 
      ref={containerRef}
      style={containerStyle}
      onScroll={handleScroll}
      role="list"
      aria-label="Virtualized list"
    >
      <div style={{ height: innerHeight, position: "relative" }}>
        <div style={{ transform, position: "absolute", width: "100%" }}>
          {items.slice(startIndex, endIndex + 1).map((item, index) => {
            const actualIndex = startIndex + index;
            return (
              <div
                key={item.id || actualIndex}
                style={{ height: itemHeight }}
                role="listitem"
                aria-posinset={actualIndex + 1}
                aria-setsize={totalItems}
              >
                {renderItem(item, actualIndex)}
              </div>
            );
          })}
        </div>
      </div>
      
      {loading && (
        <div style={{ textAlign: "center", padding: "20px" }}>
          Loading more items...
        </div>
      )}
    </div>
  );
}

// 2. Infinite scroll hook
function useInfiniteScroll(fetchFn, initialData = []) {
  const [items, setItems] = useState(initialData);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [error, setError] = useState(null);
  
  const loadMore = useCallback(async () => {
    if (loading || !hasMore) return;
    
    setLoading(true);
    setError(null);
    
    try {
      const result = await fetchFn(page);
      
      setItems(prev => [...prev, ...result.data]);
      setHasMore(result.hasMore);
      setPage(prev => prev + 1);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  }, [page, loading, hasMore, fetchFn]);
  
  const reset = useCallback(() => {
    setItems(initialData);
    setPage(1);
    setHasMore(true);
    setError(null);
  }, [initialData]);
  
  return {
    items,
    loading,
    error,
    hasMore,
    loadMore,
    reset
  };
}

// 3. Lazy image component
function LazyImage({ src, alt, width, height }) {
  const [isLoaded, setIsLoaded] = useState(false);
  const [isInView, setIsInView] = useState(false);
  const imgRef = useRef();
  const placeholderRef = useRef();
  
  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsInView(true);
          observer.unobserve(entry.target);
        }
      },
      { rootMargin: "50px" }
    );
    
    if (placeholderRef.current) {
      observer.observe(placeholderRef.current);
    }
    
    return () => observer.disconnect();
  }, []);
  
  return (
    <div 
      ref={placeholderRef}
      style={{ 
        width,
        height,
        backgroundColor: "#f0f0f0",
        position: "relative"
      }}
    >
      {isInView && (
        <img
          ref={imgRef}
          src={src}
          alt={alt}
          style={{
            width: "100%",
            height: "100%",
            objectFit: "cover",
            opacity: isLoaded ? 1 : 0,
            transition: "opacity 0.3s"
          }}
          onLoad={() => setIsLoaded(true)}
          loading="lazy"
        />
      )}
      
      {!isLoaded && (
        <div style={{
          position: "absolute",
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          display: "flex",
          alignItems: "center",
          justifyContent: "center"
        }}>
          <div className="spinner" />
        </div>
      )}
    </div>
  );
}

// 4. Complete example
function InfiniteProductList() {
  const fetchProducts = useCallback(async (page) => {
    const response = await fetch(`/api/products?page=${page}&limit=20`);
    const data = await response.json();
    
    return {
      data: data.products,
      hasMore: data.page < data.totalPages
    };
  }, []);
  
  const {
    items: products,
    loading,
    error,
    hasMore,
    loadMore
  } = useInfiniteScroll(fetchProducts, []);
  
  const renderProduct = useCallback((product, index) => (
    <div style={{
      display: "flex",
      padding: "10px",
      borderBottom: "1px solid #eee"
    }}>
      <LazyImage
        src={product.image}
        alt={product.name}
        width={100}
        height={100}
      />
      <div style={{ marginLeft: "20px" }}>
        <h3>{product.name}</h3>
        <p>${product.price}</p>
      </div>
    </div>
  ), []);
  
  return (
    <div>
      <h2>Products ({products.length})</h2>
      
      {error && (
        <div style={{ color: "red", padding: "10px" }}>
          Error loading products. 
          <button onClick={loadMore}>Retry</button>
        </div>
      )}
      
      <VirtualizedList
        items={products}
        itemHeight={120}
        containerHeight={600}
        renderItem={renderProduct}
        loading={loading}
        onLoadMore={loadMore}
      />
      
      {!hasMore && products.length > 0 && (
        <div style={{ textAlign: "center", padding: "20px" }}>
          No more products to load
        </div>
      )}
    </div>
  );
}

// 5. Window scrolling with intersection observer
function useInView(ref, options = {}) {
  const [isInView, setIsInView] = useState(false);
  
  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIsInView(entry.isIntersecting);
    }, options);
    
    if (ref.current) {
      observer.observe(ref.current);
    }
    
    return () => observer.disconnect();
  }, [ref, options]);
  
  return isInView;
}

Answer: Virtualization renders only visible items Infinite scroll loads data as user scrolls Lazy images with IntersectionObserver Accessibility support with ARIA attributes

VIRTUALIZED INFINITE SCROLL: Render large lists efficiently by only showing visible items. BENEFITS: 1. PERFORMANCE: Render thousands of items 2. MEMORY EFFICIENCY: Only mount visible DOM nodes 3. SMOOTH SCROLLING: No jank 4. BANDWIDTH EFFICIENCY: Load data as needed IMPLEMENTATION PATTERNS: 1. VIRTUALIZATION: - Calculate visible range - Transform container position - Render buffer items - Recycle DOM nodes 2. INFINITE SCROLL: - Detect scroll position - Load more data - Handle loading states - Prevent duplicate requests 3. LAZY LOADING: - IntersectionObserver API - Placeholder while loading - Progressive loading 4. WINDOWING: - Fixed vs variable heights - Dynamic height calculation - Smooth scrolling PERFORMANCE OPTIMIZATIONS: 1. DEBOUNCE SCROLL EVENTS: - Prevent excessive calculations - Use requestAnimationFrame - Batch updates 2. MEMOIZATION: - Memoize render functions - Cache item heights - Stable keys 3. RECYCLING: - Reuse DOM nodes - Pool components - Minimize mount/unmount ACCESSIBILITY: 1. ARIA roles: list, listitem 2. Keyboard navigation 3. Screen reader announcements 4. Focus management CHALLENGES: 1. VARIABLE HEIGHTS: - Measure item heights - Estimate and adjust - Dynamic recalculation 2. SCROLL POSITION RESTORATION: - Save scroll position - Restore after navigation - Handle dynamic content 3. TOUCH DEVICES: - Touch scrolling - Momentum scrolling - Pull-to-refresh REAL-WORLD LIBRARIES: 1. REACT WINDOW: Virtualized lists 2. REACT VIRTUALIZED: Older but feature-rich 3. TANSTACK VIRTUAL: Modern virtualizer 4. REACT-INFINITE-SCROLLER: Infinite scroll BEST PRACTICES: 1. Always implement loading states 2. Handle network errors 3. Provide alternative navigation (pagination) 4. Test with real data 5. Monitor performance metrics MEASUREMENT METRICS: 1. FPS during scroll 2. Memory usage 3. DOM node count 4. Time to interactive ASKED AT: Meta, Google, Airbnb (data-heavy applications)

virtualizationinfinite-scrollperformancelazy-loading

23. Form Handling with React Hook Form

intermediate

Implement complex form handling: 1. Validation with Yup/zod 2. Dynamic fields 3. Multi-step forms 4. File uploads 5. Performance optimization

javascript
import { useForm, Controller, useFieldArray } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

// 1. Schema validation with Yup
const userSchema = yup.object({
  name: yup.string().required("Name is required").min(2, "Too short"),
  email: yup.string().email("Invalid email").required("Email is required"),
  age: yup.number().min(18, "Must be 18+").max(100, "Too old"),
  password: yup.string()
    .required("Password is required")
    .min(8, "Must be at least 8 characters")
    .matches(/[a-z]/, "Must contain lowercase")
    .matches(/[A-Z]/, "Must contain uppercase")
    .matches(/\d/, "Must contain number"),
  confirmPassword: yup.string()
    .oneOf([yup.ref("password")], "Passwords must match")
    .required("Confirm password"),
  interests: yup.array().of(
    yup.object({
      name: yup.string().required(),
      level: yup.string().oneOf(["beginner", "intermediate", "advanced"])
    })
  ).min(1, "Select at least one interest"),
  subscription: yup.boolean(),
  avatar: yup.mixed()
    .test("fileSize", "File too large", value => 
      !value || (value && value.size <= 5000000)
    )
    .test("fileType", "Unsupported format", value =>
      !value || (value && [".jpg", ".png", ".jpeg"].includes(value.name))
    )
});

// 2. Complex form with dynamic fields
function UserForm() {
  const {
    register,
    handleSubmit,
    control,
    watch,
    formState: { errors, isSubmitting, isValid, touchedFields },
    reset,
    setValue,
    trigger
  } = useForm({
    resolver: yupResolver(userSchema),
    mode: "onChange", // Validate on change
    defaultValues: {
      name: "",
      email: "",
      age: 18,
      interests: [{ name: "", level: "beginner" }],
      subscription: true
    }
  });
  
  // Watch form values
  const subscription = watch("subscription");
  const password = watch("password");
  
  // Dynamic field array
  const { fields, append, remove } = useFieldArray({
    control,
    name: "interests"
  });
  
  // Handle file upload
  const handleFileChange = (e) => {
    const file = e.target.files[0];
    setValue("avatar", file);
    trigger("avatar"); // Trigger validation
  };
  
  // Submit handler
  const onSubmit = async (data) => {
    try {
      // Create FormData for file upload
      const formData = new FormData();
      Object.keys(data).forEach(key => {
        if (key === "avatar" && data[key]) {
          formData.append(key, data[key]);
        } else if (key === "interests") {
          formData.append(key, JSON.stringify(data[key]));
        } else {
          formData.append(key, data[key]);
        }
      });
      
      const response = await fetch("/api/users", {
        method: "POST",
        body: formData
      });
      
      if (response.ok) {
        alert("User created successfully!");
        reset();
      }
    } catch (error) {
      console.error("Error:", error);
    }
  };
  
  // Dynamic validation
  useEffect(() => {
    if (password && password.length < 8) {
      setValue("passwordStrength", "weak");
    } else if (password && password.length >= 8) {
      setValue("passwordStrength", "strong");
    }
  }, [password, setValue]);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Text input */}
      <div>
        <label>Name</label>
        <input 
          {...register("name")}
          placeholder="Enter your name"
          aria-invalid={errors.name ? "true" : "false"}
        />
        {errors.name && (
          <span role="alert">{errors.name.message}</span>
        )}
      </div>
      
      {/* Email with validation */}
      <div>
        <label>Email</label>
        <input
          type="email"
          {...register("email")}
          placeholder="email@example.com"
        />
        {errors.email && (
          <span role="alert">{errors.email.message}</span>
        )}
      </div>
      
      {/* Number input */}
      <div>
        <label>Age</label>
        <input
          type="number"
          {...register("age", { valueAsNumber: true })}
        />
        {errors.age && (
          <span role="alert">{errors.age.message}</span>
        )}
      </div>
      
      {/* Password with strength */}
      <div>
        <label>Password</label>
        <input
          type="password"
          {...register("password")}
        />
        {password && (
          <div>
            Strength: {password.length < 8 ? "Weak" : "Strong"}
          </div>
        )}
        {errors.password && (
          <span role="alert">{errors.password.message}</span>
        )}
      </div>
      
      {/* Confirm password */}
      <div>
        <label>Confirm Password</label>
        <input
          type="password"
          {...register("confirmPassword")}
        />
        {errors.confirmPassword && (
          <span role="alert">{errors.confirmPassword.message}</span>
        )}
      </div>
      
      {/* Dynamic fields */}
      <div>
        <label>Interests</label>
        {fields.map((field, index) => (
          <div key={field.id}>
            <input
              {...register(`interests.${index}.name`)}
              placeholder="Interest name"
            />
            <select
              {...register(`interests.${index}.level`)}
            >
              <option value="beginner">Beginner</option>
              <option value="intermediate">Intermediate</option>
              <option value="advanced">Advanced</option>
            </select>
            <button type="button" onClick={() => remove(index)}>
              Remove
            </button>
          </div>
        ))}
        <button 
          type="button"
          onClick={() => append({ name: "", level: "beginner" })}
        >
          Add Interest
        </button>
        {errors.interests && (
          <span role="alert">{errors.interests.message}</span>
        )}
      </div>
      
      {/* File upload */}
      <div>
        <label>Avatar</label>
        <input
          type="file"
          accept=".jpg,.jpeg,.png"
          onChange={handleFileChange}
        />
        {errors.avatar && (
          <span role="alert">{errors.avatar.message}</span>
        )}
      </div>
      
      {/* Checkbox */}
      <div>
        <label>
          <input type="checkbox" {...register("subscription")} />
          Subscribe to newsletter
        </label>
      </div>
      
      {/* Conditional field */}
      {subscription && (
        <div>
          <label>Newsletter frequency</label>
          <select {...register("frequency")}>
            <option value="daily">Daily</option>
            <option value="weekly">Weekly</option>
            <option value="monthly">Monthly</option>
          </select>
        </div>
      )}
      
      <button 
        type="submit" 
        disabled={isSubmitting || !isValid}
      >
        {isSubmitting ? "Submitting..." : "Submit"}
      </button>
      
      <button type="button" onClick={() => reset()}>
        Reset
      </button>
    </form>
  );
}

// 3. Multi-step form
function MultiStepForm() {
  const [step, setStep] = useState(1);
  const { handleSubmit, trigger, formState } = useForm();
  
  const nextStep = async () => {
    // Validate current step
    const isValid = await trigger();
    if (isValid) {
      setStep(prev => prev + 1);
    }
  };
  
  const prevStep = () => {
    setStep(prev => prev - 1);
  };
  
  return (
    <form onSubmit={handleSubmit(() => {})}>
      {step === 1 && (
        <div>
          <h2>Step 1: Personal Info</h2>
          {/* Step 1 fields */}
        </div>
      )}
      
      {step === 2 && (
        <div>
          <h2>Step 2: Address</h2>
          {/* Step 2 fields */}
        </div>
      )}
      
      {step === 3 && (
        <div>
          <h2>Step 3: Review</h2>
          {/* Review fields */}
        </div>
      )}
      
      <div>
        {step > 1 && (
          <button type="button" onClick={prevStep}>
            Previous
          </button>
        )}
        
        {step < 3 ? (
          <button type="button" onClick={nextStep}>
            Next
          </button>
        ) : (
          <button type="submit">Submit</button>
        )}
      </div>
      
      <div>
        Step {step} of 3
      </div>
    </form>
  );
}

// 4. Custom form hook
function useCustomForm(defaultValues) {
  const methods = useForm({ defaultValues });
  const [serverErrors, setServerErrors] = useState({});
  
  const handleServerError = useCallback((error) => {
    if (error.response?.data?.errors) {
      error.response.data.errors.forEach(err => {
        methods.setError(err.field, {
          type: "server",
          message: err.message
        });
      });
    }
    setServerErrors(error.response?.data?.errors || {});
  }, [methods]);
  
  return {
    ...methods,
    serverErrors,
    handleServerError
  };
}

Answer: React Hook Form with Yup validation Dynamic fields with useFieldArray Multi-step forms with validation per step File uploads with FormData

FORM HANDLING PATTERNS: Manage complex forms with validation, dynamic fields, and performance. BENEFITS: 1. PERFORMANCE: Minimal re-renders 2. FLEXIBILITY: Dynamic forms 3. VALIDATION: Client and server 4. UX: Real-time feedback KEY PATTERNS: 1. CONTROLLED VS UNCONTROLLED: - React Hook Form: Uncontrolled by default - Better performance for large forms - Use Controller for controlled components 2. VALIDATION: - Schema validation (Yup, Zod) - Real-time validation - Async validation - Cross-field validation 3. DYNAMIC FIELDS: - Add/remove fields - Field arrays - Nested fields - Conditional fields 4. FILE HANDLING: - FormData for file uploads - Client-side validation - Progress tracking - Multiple files PERFORMANCE OPTIMIZATIONS: 1. DEBOUNCE VALIDATION: - Prevent excessive validation - Use onBlur or onChange debounced 2. MEMOIZATION: - Memoize form components - Use React.memo - Stable references 3. OPTIMIZED RENDERING: - Split large forms - Lazy load form sections - Virtualize field lists ACCESSIBILITY: 1. ARIA attributes 2. Error announcements 3. Keyboard navigation 4. Screen reader support ERROR HANDLING: 1. Client-side validation 2. Server-side validation 3. Network errors 4. Form submission errors REAL-WORLD LIBRARIES: 1. REACT HOOK FORM: Performance focused 2. FORMIK: Feature rich 3. FINAL FORM: Predictable 4. REACT FINAL FORM: Formik + Final Form BEST PRACTICES: 1. Use schema validation 2. Handle server errors 3. Provide clear error messages 4. Implement loading states 5. Support form reset TESTING: 1. Unit test validation 2. Integration test flows 3. E2E test submissions 4. Accessibility testing ASKED AT: Meta, Google, Stripe (form-heavy applications)

formsvalidationreact-hook-formperformance

24. Authentication Patterns in React

advanced

Implement JWT authentication: 1. Login/logout flows 2. Token refresh 3. Protected routes 4. Role-based access 5. Social login (OAuth)

javascript
// 1. Auth context provider
const AuthContext = createContext();

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  // Initialize auth state
  useEffect(() => {
    const initAuth = async () => {
      try {
        // Check for stored token
        const token = localStorage.getItem("token");
        
        if (token) {
          // Validate token
          const user = await validateToken(token);
          setUser(user);
        }
      } catch (err) {
        console.error("Auth init error:", err);
        localStorage.removeItem("token");
        localStorage.removeItem("refreshToken");
      } finally {
        setLoading(false);
      }
    };
    
    initAuth();
  }, []);
  
  // Login function
  const login = async (credentials) => {
    setError(null);
    
    try {
      const response = await fetch("/api/auth/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(credentials)
      });
      
      if (!response.ok) {
        throw new Error("Login failed");
      }
      
      const { user, token, refreshToken } = await response.json();
      
      // Store tokens
      localStorage.setItem("token", token);
      localStorage.setItem("refreshToken", refreshToken);
      
      // Set user
      setUser(user);
      
      return { success: true, user };
      
    } catch (err) {
      setError(err.message);
      return { success: false, error: err.message };
    }
  };
  
  // Logout function
  const logout = () => {
    // Clear storage
    localStorage.removeItem("token");
    localStorage.removeItem("refreshToken");
    
    // Clear user
    setUser(null);
    
    // Optional: Call logout endpoint
    fetch("/api/auth/logout", { method: "POST" });
  };
  
  // Refresh token
  const refreshAuthToken = async () => {
    try {
      const refreshToken = localStorage.getItem("refreshToken");
      
      if (!refreshToken) {
        throw new Error("No refresh token");
      }
      
      const response = await fetch("/api/auth/refresh", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ refreshToken })
      });
      
      if (!response.ok) {
        throw new Error("Token refresh failed");
      }
      
      const { token, refreshToken: newRefreshToken } = await response.json();
      
      // Update tokens
      localStorage.setItem("token", token);
      localStorage.setItem("refreshToken", newRefreshToken);
      
      return token;
      
    } catch (err) {
      logout();
      throw err;
    }
  };
  
  // Update user
  const updateUser = (updates) => {
    setUser(prev => ({ ...prev, ...updates }));
  };
  
  const value = {
    user,
    loading,
    error,
    login,
    logout,
    refreshAuthToken,
    updateUser,
    isAuthenticated: !!user
  };
  
  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

// 2. Protected route component
function ProtectedRoute({ children, roles = [] }) {
  const { user, loading, isAuthenticated } = useAuth();
  const location = useLocation();
  
  if (loading) {
    return <div>Loading auth...</div>;
  }
  
  if (!isAuthenticated) {
    // Redirect to login
    return <Navigate to="/login" state={{ from: location }} replace />;
  }
  
  // Check roles if specified
  if (roles.length > 0 && user && !roles.includes(user.role)) {
    return <Navigate to="/unauthorized" replace />;
  }
  
  return children;
}

// 3. Auth hook
function useAuth() {
  const context = useContext(AuthContext);
  
  if (!context) {
    throw new Error("useAuth must be used within AuthProvider");
  }
  
  return context;
}

// 4. Axios interceptor for token refresh
function setupAxiosInterceptors(refreshAuthToken, logout) {
  let isRefreshing = false;
  let failedQueue = [];
  
  const processQueue = (error, token = null) => {
    failedQueue.forEach(prom => {
      if (error) {
        prom.reject(error);
      } else {
        prom.resolve(token);
      }
    });
    
    failedQueue = [];
  };
  
  axios.interceptors.request.use(
    (config) => {
      const token = localStorage.getItem("token");
      
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      
      return config;
    },
    (error) => Promise.reject(error)
  );
  
  axios.interceptors.response.use(
    (response) => response,
    async (error) => {
      const originalRequest = error.config;
      
      // If 401 and not a retry
      if (error.response?.status === 401 && !originalRequest._retry) {
        
        if (isRefreshing) {
          // Queue the request
          return new Promise((resolve, reject) => {
            failedQueue.push({ resolve, reject });
          })
            .then(token => {
              originalRequest.headers.Authorization = `Bearer ${token}`;
              return axios(originalRequest);
            })
            .catch(err => Promise.reject(err));
        }
        
        originalRequest._retry = true;
        isRefreshing = true;
        
        try {
          const newToken = await refreshAuthToken();
          
          // Update Authorization header
          originalRequest.headers.Authorization = `Bearer ${newToken}`;
          
          // Process queued requests
          processQueue(null, newToken);
          
          // Retry original request
          return axios(originalRequest);
          
        } catch (refreshError) {
          processQueue(refreshError, null);
          logout();
          return Promise.reject(refreshError);
          
        } finally {
          isRefreshing = false;
        }
      }
      
      return Promise.reject(error);
    }
  );
}

// 5. Social login component
function SocialLogin({ provider }) {
  const { login } = useAuth();
  
  const handleSocialLogin = async () => {
    // Open OAuth window
    const width = 600;
    const height = 600;
    const left = window.screenX + (window.outerWidth - width) / 2;
    const top = window.screenY + (window.outerHeight - height) / 2;
    
    const url = `/api/auth/${provider}`;
    
    const popup = window.open(
      url,
      `${provider} Login`,
      `width=${width},height=${height},left=${left},top=${top}`
    );
    
    // Listen for message from popup
    const messageHandler = (event) => {
      if (event.origin !== window.location.origin) return;
      
      if (event.data.type === "OAUTH_SUCCESS") {
        const { token, user } = event.data;
        
        // Store token
        localStorage.setItem("token", token);
        
        // Update auth context
        login({ token, user });
        
        // Cleanup
        window.removeEventListener("message", messageHandler);
        popup.close();
      }
    };
    
    window.addEventListener("message", messageHandler);
  };
  
  return (
    <button onClick={handleSocialLogin}>
      Continue with {provider}
    </button>
  );
}

// 6. Role-based component
function RoleGuard({ children, roles }) {
  const { user } = useAuth();
  
  if (!user || !roles.includes(user.role)) {
    return null;
  }
  
  return children;
}

// 7. App setup with auth
function App() {
  return (
    <AuthProvider>
      <Router>
        <Routes>
          {/* Public routes */}
          <Route path="/login" element={<LoginPage />} />
          <Route path="/register" element={<RegisterPage />} />
          
          {/* Protected routes */}
          <Route path="/dashboard" element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          } />
          
          <Route path="/admin" element={
            <ProtectedRoute roles={["admin"]}>
              <AdminPanel />
            </ProtectedRoute>
          } />
        </Routes>
      </Router>
    </AuthProvider>
  );
}

Answer: JWT authentication with token refresh Protected routes and role-based access Social login with OAuth Axios interceptors for automatic token refresh

AUTHENTICATION PATTERNS: Secure user authentication and authorization in React apps. AUTH METHODS: 1. JWT (JSON WEB TOKENS): - Stateless authentication - Access + refresh tokens - Token expiration - Blacklisting 2. SESSIONS: - Server-side sessions - Cookie-based - CSRF protection - Session storage 3. OAUTH/SOCIAL LOGIN: - Google, Facebook, GitHub - OAuth 2.0 flow - Popup/redirect - Token exchange SECURITY PATTERNS: 1. TOKEN STORAGE: - HttpOnly cookies (most secure) - localStorage (SPA-friendly) - sessionStorage (tab-scoped) - In-memory (most secure, but no persistence) 2. TOKEN REFRESH: - Silent refresh - Refresh token rotation - Concurrent request handling - Failed queue management 3. CSRF PROTECTION: - SameSite cookies - CSRF tokens - Double submit cookies IMPLEMENTATION PATTERNS: 1. AUTH PROVIDER: - Context API - Global auth state - Auth methods 2. PROTECTED ROUTES: - Route guards - Conditional rendering - Redirects 3. ROLE-BASED ACCESS: - User roles/permissions - Component-level guards - Route-level guards 4. SOCIAL LOGIN: - Popup windows - PostMessage communication - Token validation PERFORMANCE OPTIMIZATIONS: - Lazy load auth providers - Cache user data - Minimize token validation requests - Optimize auth state updates ERROR HANDLING: 1. Token expiration 2. Network failures 3. Invalid tokens 4. Server errors BEST PRACTICES: 1. Use HTTPS always 2. Implement proper CORS 3. Validate tokens server-side 4. Log security events 5. Rate limiting REAL-WORLD LIBRARIES: 1. NEXT-AUTH: Next.js authentication 2. AUTH0: Enterprise auth 3. FIREBASE AUTH: Google auth service 4. PASSPORT.JS: Node.js middleware TESTING: 1. Unit test auth logic 2. Integration test flows 3. E2E test login/logout 4. Security testing ASKED AT: Meta, Google, Stripe (security-focused roles)

authenticationjwtsecurityoauth

25. Internationalization (i18n) Patterns

intermediate

Implement i18n in React: 1. Translation files 2. Language switching 3. Pluralization 4. Date/number formatting 5. RTL (Right-to-Left) support

javascript
// 1. Translation files
const translations = {
  en: {
    welcome: "Welcome, {{name}}!",
    products: {
      one: "{{count}} product",
      other: "{{count}} products"
    },
    date: "Today is {{date, datetime}}",
    price: "Price: {{price, currency}}",
    buttons: {
      save: "Save",
      cancel: "Cancel"
    }
  },
  fr: {
    welcome: "Bienvenue, {{name}} !",
    products: {
      one: "{{count}} produit",
      other: "{{count}} produits"
    },
    date: "Aujourd'hui, c'est le {{date, datetime}}",
    price: "Prix : {{price, currency}}",
    buttons: {
      save: "Enregistrer",
      cancel: "Annuler"
    }
  },
  ar: {
    welcome: "مرحبًا {{name}}!",
    products: {
      one: "{{count}} منتج",
      other: "{{count}} منتجات"
    },
    date: "اليوم هو {{date, datetime}}",
    price: "السعر: {{price, currency}}",
    buttons: {
      save: "حفظ",
      cancel: "إلغاء"
    }
  }
};

// 2. i18n context
const I18nContext = createContext();

function I18nProvider({ children }) {
  const [locale, setLocale] = useState(
    () => localStorage.getItem("locale") || "en"
  );
  const [direction, setDirection] = useState("ltr");
  
  // Update direction based on locale
  useEffect(() => {
    const newDirection = ["ar", "he"].includes(locale) ? "rtl" : "ltr";
    setDirection(newDirection);
    
    // Update HTML dir attribute
    document.documentElement.dir = newDirection;
    document.documentElement.lang = locale;
  }, [locale]);
  
  // Format message
  const formatMessage = (id, values = {}) => {
    const keys = id.split(".");
    let message = keys.reduce((obj, key) => obj?.[key], translations[locale]);
    
    if (!message) {
      console.warn(`Translation missing: ${id} for locale ${locale}`);
      return id;
    }
    
    // Handle pluralization
    if (typeof message === "object" && "one" in message && "other" in message) {
      const count = values.count || 0;
      message = count === 1 ? message.one : message.other;
    }
    
    // Replace variables
    return message.replace(/\{\{(.+?)\}\}/g, (match, key) => {
      const [varName, format] = key.trim().split(",");
      const value = values[varName.trim()];
      
      if (format) {
        return formatValue(value, format.trim());
      }
      
      return value != null ? value : match;
    });
  };
  
  // Format values based on type
  const formatValue = (value, format) => {
    switch (format) {
      case "datetime":
        return new Intl.DateTimeFormat(locale, {
          dateStyle: "long",
          timeStyle: "short"
        }).format(new Date(value));
        
      case "currency":
        return new Intl.NumberFormat(locale, {
          style: "currency",
          currency: locale === "en" ? "USD" : "EUR"
        }).format(value);
        
      case "number":
        return new Intl.NumberFormat(locale).format(value);
        
      case "percent":
        return new Intl.NumberFormat(locale, {
          style: "percent"
        }).format(value);
        
      default:
        return value;
    }
  };
  
  // Change locale
  const changeLocale = (newLocale) => {
    setLocale(newLocale);
    localStorage.setItem("locale", newLocale);
  };
  
  const value = {
    locale,
    direction,
    formatMessage,
    changeLocale,
    formatValue
  };
  
  return (
    <I18nContext.Provider value={value}>
      <div style={{ direction }}>
        {children}
      </div>
    </I18nContext.Provider>
  );
}

// 3. Custom hook
function useTranslation() {
  const context = useContext(I18nContext);
  
  if (!context) {
    throw new Error("useTranslation must be used within I18nProvider");
  }
  
  return context;
}

// 4. Translation component
function Trans({ id, values, children }) {
  const { formatMessage } = useTranslation();
  
  if (children) {
    // Extract text from children for translation
    return React.Children.map(children, child => {
      if (typeof child === "string") {
        return formatMessage(id || child, values);
      }
      return child;
    });
  }
  
  return formatMessage(id, values);
}

// 5. Usage examples
function WelcomeMessage({ name }) {
  const { formatMessage, locale } = useTranslation();
  
  return (
    <div>
      <h1>{formatMessage("welcome", { name })}</h1>
      <p>{formatMessage("date", { date: new Date() })}</p>
      <p>{formatMessage("price", { price: 19.99 })}</p>
      
      {/* Pluralization */}
      <p>{formatMessage("products", { count: 1 })}</p>
      <p>{formatMessage("products", { count: 5 })}</p>
      
      {/* Using Trans component */}
      <Trans id="buttons.save" />
      <Trans id="buttons.cancel" />
      
      {/* Language switcher */}
      <select 
        value={locale} 
        onChange={(e) => changeLocale(e.target.value)}
      >
        <option value="en">English</option>
        <option value="fr">Français</option>
        <option value="ar">العربية</option>
      </select>
    </div>
  );
}

// 6. RTL support component
function RTLWrapper({ children }) {
  const { direction } = useTranslation();
  
  return (
    <div 
      style={{
        direction,
        textAlign: direction === "rtl" ? "right" : "left"
      }}
    >
      {children}
    </div>
  );
}

// 7. Date formatting hook
function useFormattedDate(date, options = {}) {
  const { locale } = useTranslation();
  
  return useMemo(() => {
    return new Intl.DateTimeFormat(locale, {
      year: "numeric",
      month: "long",
      day: "numeric",
      ...options
    }).format(new Date(date));
  }, [date, locale, options]);
}

// 8. Number formatting hook
function useFormattedNumber(number, options = {}) {
  const { locale } = useTranslation();
  
  return useMemo(() => {
    return new Intl.NumberFormat(locale, {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
      ...options
    }).format(number);
  }, [number, locale, options]);
}

// 9. Async translation loading
function useAsyncTranslations(locale) {
  const [translations, setTranslations] = useState({});
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    const loadTranslations = async () => {
      setLoading(true);
      
      try {
        const response = await fetch(`/locales/${locale}.json`);
        const data = await response.json();
        setTranslations(data);
      } catch (error) {
        console.error("Failed to load translations:", error);
      } finally {
        setLoading(false);
      }
    };
    
    loadTranslations();
  }, [locale]);
  
  return { translations, loading };
}

// 10. App setup
function App() {
  return (
    <I18nProvider>
      <RTLWrapper>
        <WelcomeMessage name="John" />
        {/* Rest of app */}
      </RTLWrapper>
    </I18nProvider>
  );
}

Answer: Translation files with pluralization support Language switching with locale persistence Date/number formatting with Intl API RTL support for Arabic/Hebrew

INTERNATIONALIZATION (I18N) PATTERNS: Adapt applications for different languages and regions. KEY CONCEPTS: 1. LOCALIZATION (L10N): - Translations - Date/time formats - Number/currency formats - Measurement units 2. PLURALIZATION: - Language-specific plural rules - One, few, many, other - ICU MessageFormat 3. RTL SUPPORT: - Right-to-left languages - Text alignment - Layout flipping - Bi-directional text IMPLEMENTATION PATTERNS: 1. TRANSLATION FILES: - JSON structure - Nested keys - Variables/interpolation - Plural forms 2. LANGUAGE SWITCHING: - Context/Redux - URL-based locale - Browser detection - User preference 3. FORMATTING: - Intl API (DateTimeFormat, NumberFormat) - Locale-aware formatting - Timezone support - Calendar systems PERFORMANCE OPTIMIZATIONS: 1. LAZY LOADING: - Load translations on demand - Split by locale - Code splitting 2. CACHING: - Cache translations - Service worker - CDN hosting 3. BUNDLE OPTIMIZATION: - Tree shaking - Remove unused translations - Compression ACCESSIBILITY: 1. Language attribute 2. Direction attribute 3. Screen reader support 4. Keyboard navigation BEST PRACTICES: 1. Use ICU MessageFormat 2. Support RTL early 3. Test with long translations 4. Handle missing translations 5. Provide translation keys REAL-WORLD LIBRARIES: 1. REACT-I18NEXT: Popular i18n framework 2. FORMATJS: ICU MessageFormat 3. LINGUI.JS: Modern i18n 4. I18NEXT: Framework agnostic TESTING: 1. Test all locales 2. Test RTL layout 3. Test date/number formats 4. Test pluralization DEPLOYMENT: 1. Translation management systems 2. Continuous localization 3. Over-the-air updates 4. A/B testing translations ASKED AT: Meta, Google, Microsoft (global products)

i18ninternationalizationlocalizationrtl

26. Micro-frontends with Module Federation

advanced

Implement micro-frontends using Webpack Module Federation: 1. Host and remote applications 2. Shared dependencies 3. Dynamic component loading 4. Cross-app communication 5. Deployment strategies

javascript
// 1. Host app webpack.config.js
module.exports = {
  // ...
  plugins: [
    new ModuleFederationPlugin({
      name: "host",
      remotes: {
        nav: "nav@http://localhost:3001/remoteEntry.js",
        dashboard: "dashboard@http://localhost:3002/remoteEntry.js",
        auth: "auth@http://localhost:3003/remoteEntry.js"
      },
      shared: {
        react: { singleton: true, requiredVersion: "^18.0.0" },
        "react-dom": { singleton: true, requiredVersion: "^18.0.0" },
        "react-router-dom": { singleton: true, requiredVersion: "^6.0.0" },
        "@reduxjs/toolkit": { singleton: true },
        // Shared utilities
        "shared-utils": { singleton: true }
      }
    })
  ]
};

// 2. Remote app (navbar) webpack.config.js
module.exports = {
  // ...
  plugins: [
    new ModuleFederationPlugin({
      name: "nav",
      filename: "remoteEntry.js",
      exposes: {
        "./Navbar": "./src/components/Navbar",
        "./Footer": "./src/components/Footer",
        "./Header": "./src/components/Header"
      },
      shared: {
        react: { singleton: true, requiredVersion: "^18.0.0" },
        "react-dom": { singleton: true, requiredVersion: "^18.0.0" }
      }
    })
  ]
};

// 3. Host app loading remote components
function App() {
  const [Navbar, setNavbar] = useState(null);
  const [Dashboard, setDashboard] = useState(null);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    // Dynamic import of remote modules
    const loadRemotes = async () => {
      try {
        // Load navbar
        const navModule = await import("nav/Navbar");
        setNavbar(() => navModule.default);
        
        // Load dashboard (lazy)
        const dashboardModule = await import("dashboard/Dashboard");
        setDashboard(() => dashboardModule.default);
        
      } catch (err) {
        setError("Failed to load remote modules");
        console.error(err);
      }
    };
    
    loadRemotes();
  }, []);
  
  if (error) {
    return <div>Error: {error}</div>;
  }
  
  return (
    <div>
      {/* Loaded remote components */}
      {Navbar && <Navbar />}
      
      <main>
        {Dashboard ? (
          <Suspense fallback={<div>Loading dashboard...</div>}>
            <Dashboard />
          </Suspense>
        ) : (
          <div>Loading dashboard...</div>
        )}
      </main>
      
      {/* Local component */}
      <LocalComponent />
    </div>
  );
}

// 4. Cross-app communication with custom events
const EventBus = {
  events: {},
  
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  },
  
  off(event, callback) {
    if (!this.events[event]) return;
    
    const index = this.events[event].indexOf(callback);
    if (index > -1) {
      this.events[event].splice(index, 1);
    }
  },
  
  emit(event, data) {
    if (!this.events[event]) return;
    
    this.events[event].forEach(callback => {
      try {
        callback(data);
      } catch (err) {
        console.error(`Error in event handler for ${event}:`, err);
      }
    });
  }
};

// Usage in micro-frontends
function Navbar() {
  const handleLogout = () => {
    EventBus.emit("user:logout", { userId: 123 });
  };
  
  return (
    <nav>
      <button onClick={handleLogout}>Logout</button>
    </nav>
  );
}

function Dashboard() {
  useEffect(() => {
    const handleLogout = (data) => {
      console.log("Logout event received:", data);
      // Clear dashboard data
    };
    
    EventBus.on("user:logout", handleLogout);
    
    return () => {
      EventBus.off("user:logout", handleLogout);
    };
  }, []);
  
  return <div>Dashboard content</div>;
}

// 5. Shared state management
const SharedStateContext = createContext();

function SharedStateProvider({ children }) {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState("light");
  
  // Sync state across micro-frontends
  useEffect(() => {
    const handleThemeChange = (data) => {
      setTheme(data.theme);
    };
    
    EventBus.on("theme:change", handleThemeChange);
    
    return () => {
      EventBus.off("theme:change", handleThemeChange);
    };
  }, []);
  
  const value = {
    user,
    theme,
    setUser,
    setTheme: (newTheme) => {
      setTheme(newTheme);
      EventBus.emit("theme:change", { theme: newTheme });
    }
  };
  
  return (
    <SharedStateContext.Provider value={value}>
      {children}
    </SharedStateContext.Provider>
  );
}

// 6. Dynamic remote loading with error boundary
function RemoteComponent({ remote, module, fallback, ...props }) {
  const [Component, setComponent] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const loadComponent = async () => {
      try {
        setLoading(true);
        setError(null);
        
        // Import remote module
        const module = await import(/* webpackIgnore: true */ remote);
        setComponent(() => module.default);
        
      } catch (err) {
        setError(err.message);
        console.error(`Failed to load ${remote}:`, err);
      } finally {
        setLoading(false);
      }
    };
    
    loadComponent();
  }, [remote]);
  
  if (loading) return fallback || <div>Loading...</div>;
  if (error) return <div>Error loading component: {error}</div>;
  if (!Component) return null;
  
  return <Component {...props} />;
}

// Usage
<RemoteComponent
  remote="http://localhost:3001/remoteEntry.js"
  module="./Navbar"
  fallback={<div>Loading navbar...</div>}
/>

// 7. Version management
const RemoteVersionManager = {
  versions: {
    nav: "1.2.0",
    dashboard: "2.1.0",
    auth: "1.0.0"
  },
  
  getRemoteUrl(moduleName) {
    const version = this.versions[moduleName];
    return `https://cdn.example.com/${moduleName}/${version}/remoteEntry.js`;
  },
  
  updateVersion(moduleName, newVersion) {
    this.versions[moduleName] = newVersion;
    // Emit event to reload component
    EventBus.emit("module:update", { module: moduleName, version: newVersion });
  }
};

// 8. Deployment strategy
/*
Production deployment:
1. Each micro-frontend deployed independently
2. CDN for static assets
3. Versioned remoteEntry.js files
4. Blue-green deployment
5. Canary releases

Example CDN URLs:
- https://cdn.example.com/nav/1.2.0/remoteEntry.js
- https://cdn.example.com/dashboard/2.1.0/remoteEntry.js
- https://cdn.example.com/auth/1.0.0/remoteEntry.js
*/

Answer: Module Federation for micro-frontends Shared dependencies and singleton React Cross-app communication with event bus Dynamic remote loading with error handling

MICRO-FRONTENDS PATTERN: Split large applications into smaller, independently deployable frontend applications. BENEFITS: 1. INDEPENDENT DEPLOYMENT: Teams deploy independently 2. TECHNOLOGY AGNOSTIC: Different frameworks 3. SCALABILITY: Scale teams and codebase 4. FASTER DEVELOPMENT: Parallel development ARCHITECTURE PATTERNS: 1. BUILD-TIME INTEGRATION: - NPM packages - Monorepo - Shared components 2. RUN-TIME INTEGRATION: - Webpack Module Federation - iframe integration - Web Components 3. SERVER-SIDE INTEGRATION: - Edge Side Includes - Server-side composition - API Gateway KEY CONCEPTS: 1. HOST APPLICATION: - Shell/container app - Loads remote modules - Provides shared dependencies 2. REMOTE APPLICATION: - Exposes components - Independent deployment - Versioned releases 3. SHARED DEPENDENCIES: - Singleton React - Shared state management - Common utilities CHALLENGES: 1. STATE MANAGEMENT: - Cross-app state sharing - Event-based communication - Shared context 2. STYLING: - CSS isolation - Design system consistency - Theme propagation 3. ROUTING: - Cross-app navigation - Nested routes - Route synchronization 4. PERFORMANCE: - Bundle size optimization - Lazy loading - Caching strategies DEPLOYMENT STRATEGIES: 1. INDEPENDENT: Each app has own pipeline 2. COORDINATED: Synchronized releases 3. CANARY: Gradual rollout 4. BLUE-GREEN: Zero downtime TOOLING: 1. WEBPACK MODULE FEDERATION: Runtime integration 2. SINGLE-SPA: Framework-agnostic 3. BIT: Component-driven 4. NX: Monorepo tooling BEST PRACTICES: 1. Define clear contracts 2. Version APIs 3. Implement error boundaries 4. Monitor performance 5. Test integration points REAL-WORLD USERS: 1. SPOTIFY: Web player 2. IKEA: E-commerce 3. DAILYMOTION: Video platform 4. AMAZON: Retail website ASKED AT: Amazon, Spotify, Microsoft (large-scale applications)

micro-frontendsmodule-federationarchitecturewebpack

27. Design System Component Library

advanced

Build a design system component library: 1. Theme provider with tokens 2. Consistent component API 3. Storybook documentation 4. Accessibility compliance 5. Performance optimization

javascript
// 1. Theme tokens
const themeTokens = {
  colors: {
    primary: {
      50: "#eff6ff",
      100: "#dbeafe",
      200: "#bfdbfe",
      300: "#93c5fd",
      400: "#60a5fa",
      500: "#3b82f6",
      600: "#2563eb",
      700: "#1d4ed8",
      800: "#1e40af",
      900: "#1e3a8a"
    },
    neutral: {
      50: "#f9fafb",
      100: "#f3f4f6",
      200: "#e5e7eb",
      300: "#d1d5db",
      400: "#9ca3af",
      500: "#6b7280",
      600: "#4b5563",
      700: "#374151",
      800: "#1f2937",
      900: "#111827"
    }
  },
  typography: {
    fontFamily: {
      sans: ["Inter", "sans-serif"],
      mono: ["Roboto Mono", "monospace"]
    },
    fontSize: {
      xs: "0.75rem",    // 12px
      sm: "0.875rem",   // 14px
      base: "1rem",     // 16px
      lg: "1.125rem",   // 18px
      xl: "1.25rem",    // 20px
      "2xl": "1.5rem",  // 24px
      "3xl": "1.875rem", // 30px
      "4xl": "2.25rem"  // 36px
    },
    fontWeight: {
      normal: 400,
      medium: 500,
      semibold: 600,
      bold: 700
    }
  },
  spacing: {
    0: "0",
    1: "0.25rem",  // 4px
    2: "0.5rem",   // 8px
    3: "0.75rem",  // 12px
    4: "1rem",     // 16px
    6: "1.5rem",   // 24px
    8: "2rem",     // 32px
    12: "3rem",    // 48px
    16: "4rem"     // 64px
  },
  borderRadius: {
    none: "0",
    sm: "0.125rem",  // 2px
    base: "0.25rem", // 4px
    md: "0.375rem",  // 6px
    lg: "0.5rem",    // 8px
    xl: "0.75rem",   // 12px
    "2xl": "1rem",   // 16px
    full: "9999px"
  }
};

// 2. Theme context
const ThemeContext = createContext();

function DesignSystemProvider({ children, theme = themeTokens }) {
  const [mode, setMode] = useState("light");
  
  const currentTheme = useMemo(() => ({
    ...theme,
    mode,
    colors: {
      ...theme.colors,
      background: mode === "light" ? "#ffffff" : "#111827",
      text: mode === "light" ? "#111827" : "#f9fafb"
    }
  }), [theme, mode]);
  
  const toggleMode = useCallback(() => {
    setMode(prev => prev === "light" ? "dark" : "light");
  }, []);
  
  return (
    <ThemeContext.Provider value={{ theme: currentTheme, toggleMode, mode }}>
      <GlobalStyles theme={currentTheme} />
      {children}
    </ThemeContext.Provider>
  );
}

// Global styles
function GlobalStyles({ theme }) {
  return (
    <style>
      {`
        :root {
          --color-primary-500: ${theme.colors.primary[500]};
          --color-neutral-500: ${theme.colors.neutral[500]};
          --font-family-sans: ${theme.typography.fontFamily.sans.join(", ")};
          --spacing-4: ${theme.spacing[4]};
          --radius-base: ${theme.borderRadius.base};
        }
        
        body {
          font-family: var(--font-family-sans);
          background-color: ${theme.colors.background};
          color: ${theme.colors.text};
          transition: background-color 0.3s, color 0.3s;
        }
      `}
    </style>
  );
}

// 3. Button component with variants
const Button = React.forwardRef(function Button({
  children,
  variant = "primary",
  size = "medium",
  isLoading = false,
  disabled = false,
  leftIcon,
  rightIcon,
  ...props
}, ref) {
  const { theme } = useTheme();
  
  const baseStyles = {
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    fontWeight: theme.typography.fontWeight.medium,
    border: "1px solid transparent",
    borderRadius: theme.borderRadius.base,
    cursor: disabled ? "not-allowed" : "pointer",
    transition: "all 0.2s",
    outline: "none",
    "&:focus-visible": {
      boxShadow: `0 0 0 3px ${theme.colors.primary[100]}`
    }
  };
  
  const variants = {
    primary: {
      backgroundColor: theme.colors.primary[600],
      color: "white",
      "&:hover:not(:disabled)": {
        backgroundColor: theme.colors.primary[700]
      },
      "&:active:not(:disabled)": {
        backgroundColor: theme.colors.primary[800]
      }
    },
    secondary: {
      backgroundColor: theme.colors.neutral[200],
      color: theme.colors.neutral[800],
      "&:hover:not(:disabled)": {
        backgroundColor: theme.colors.neutral[300]
      }
    },
    ghost: {
      backgroundColor: "transparent",
      color: theme.colors.neutral[700],
      "&:hover:not(:disabled)": {
        backgroundColor: theme.colors.neutral[100]
      }
    }
  };
  
  const sizes = {
    small: {
      padding: `${theme.spacing[1]} ${theme.spacing[2]}`,
      fontSize: theme.typography.fontSize.sm
    },
    medium: {
      padding: `${theme.spacing[2]} ${theme.spacing[4]}`,
      fontSize: theme.typography.fontSize.base
    },
    large: {
      padding: `${theme.spacing[3]} ${theme.spacing[6]}`,
      fontSize: theme.typography.fontSize.lg
    }
  };
  
  const styles = {
    ...baseStyles,
    ...variants[variant],
    ...sizes[size],
    opacity: disabled ? 0.6 : 1
  };
  
  return (
    <button
      ref={ref}
      style={styles}
      disabled={disabled || isLoading}
      aria-busy={isLoading}
      {...props}
    >
      {isLoading && (
        <Spinner size="sm" color="currentColor" />
      )}
      
      {!isLoading && leftIcon && (
        <span style={{ marginRight: theme.spacing[1] }}>
          {leftIcon}
        </span>
      )}
      
      {children}
      
      {!isLoading && rightIcon && (
        <span style={{ marginLeft: theme.spacing[1] }}>
          {rightIcon}
        </span>
      )}
    </button>
  );
});

// 4. Input component
const Input = React.forwardRef(function Input({
  label,
  error,
  helperText,
  required,
  disabled,
  leftElement,
  rightElement,
  ...props
}, ref) {
  const { theme } = useTheme();
  const id = useId();
  
  return (
    <div style={{ marginBottom: theme.spacing[4] }}>
      {label && (
        <label 
          htmlFor={id}
          style={{
            display: "block",
            marginBottom: theme.spacing[1],
            fontWeight: theme.typography.fontWeight.medium,
            color: error ? theme.colors.danger : theme.colors.neutral[700]
          }}
        >
          {label}
          {required && (
            <span style={{ color: theme.colors.danger }}>*</span>
          )}
        </label>
      )}
      
      <div style={{ position: "relative" }}>
        {leftElement && (
          <div style={{
            position: "absolute",
            left: theme.spacing[2],
            top: "50%",
            transform: "translateY(-50%)"
          }}>
            {leftElement}
          </div>
        )}
        
        <input
          ref={ref}
          id={id}
          style={{
            width: "100%",
            padding: `${theme.spacing[2]} ${theme.spacing[3]}`,
            paddingLeft: leftElement ? `calc(${theme.spacing[3]} + 24px)` : theme.spacing[3],
            paddingRight: rightElement ? `calc(${theme.spacing[3]} + 24px)` : theme.spacing[3],
            border: `1px solid ${error ? theme.colors.danger : theme.colors.neutral[300]}`,
            borderRadius: theme.borderRadius.base,
            fontSize: theme.typography.fontSize.base,
            color: theme.colors.neutral[900],
            backgroundColor: disabled ? theme.colors.neutral[100] : "white",
            transition: "border-color 0.2s",
            "&:focus": {
              outline: "none",
              borderColor: error ? theme.colors.danger : theme.colors.primary[500],
              boxShadow: `0 0 0 3px ${error ? theme.colors.dangerLight : theme.colors.primary[100]}`
            },
            "&:disabled": {
              cursor: "not-allowed",
              opacity: 0.6
            }
          }}
          disabled={disabled}
          aria-invalid={error ? "true" : "false"}
          aria-describedby={error ? `${id}-error` : helperText ? `${id}-helper` : undefined}
          {...props}
        />
        
        {rightElement && (
          <div style={{
            position: "absolute",
            right: theme.spacing[2],
            top: "50%",
            transform: "translateY(-50%)"
          }}>
            {rightElement}
          </div>
        )}
      </div>
      
      {error && (
        <div 
          id={`${id}-error`}
          style={{
            marginTop: theme.spacing[1],
            color: theme.colors.danger,
            fontSize: theme.typography.fontSize.sm
          }}
          role="alert"
        >
          {error}
        </div>
      )}
      
      {helperText && !error && (
        <div 
          id={`${id}-helper`}
          style={{
            marginTop: theme.spacing[1],
            color: theme.colors.neutral[500],
            fontSize: theme.typography.fontSize.sm
          }}
        >
          {helperText}
        </div>
      )}
    </div>
  );
});

// 5. Compound components (Accordion)
const AccordionContext = createContext();

function Accordion({ children, allowMultiple = false }) {
  const [openItems, setOpenItems] = useState([]);
  
  const toggleItem = useCallback((itemId) => {
    setOpenItems(prev => {
      if (allowMultiple) {
        return prev.includes(itemId)
          ? prev.filter(id => id !== itemId)
          : [...prev, itemId];
      } else {
        return prev.includes(itemId) ? [] : [itemId];
      }
    });
  }, [allowMultiple]);
  
  return (
    <AccordionContext.Provider value={{ openItems, toggleItem }}>
      <div role="region">{children}</div>
    </AccordionContext.Provider>
  );
}

function AccordionItem({ children, id }) {
  const { openItems, toggleItem } = useContext(AccordionContext);
  const isOpen = openItems.includes(id);
  
  return (
    <div style={{ borderBottom: "1px solid #e5e7eb" }}>
      {React.Children.map(children, child =>
        React.cloneElement(child, { isOpen, toggle: () => toggleItem(id) })
      )}
    </div>
  );
}

function AccordionTrigger({ children, isOpen, toggle }) {
  return (
    <button
      onClick={toggle}
      aria-expanded={isOpen}
      style={{
        width: "100%",
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
        padding: "1rem",
        backgroundColor: "transparent",
        border: "none",
        cursor: "pointer"
      }}
    >
      {children}
      <span>{isOpen ? "▼" : "▶"}</span>
    </button>
  );
}

function AccordionContent({ children, isOpen }) {
  return (
    <div
      style={{
        padding: isOpen ? "1rem" : "0 1rem",
        maxHeight: isOpen ? "1000px" : "0",
        overflow: "hidden",
        transition: "all 0.3s"
      }}
      aria-hidden={!isOpen}
    >
      {children}
    </div>
  );
}

// Usage
<Accordion allowMultiple>
  <AccordionItem id="1">
    <AccordionTrigger>Section 1</AccordionTrigger>
    <AccordionContent>Content 1</AccordionContent>
  </AccordionItem>
  <AccordionItem id="2">
    <AccordionTrigger>Section 2</AccordionTrigger>
    <AccordionContent>Content 2</AccordionContent>
  </AccordionItem>
</Accordion>

// 6. Storybook stories
/*
// Button.stories.js
export default {
  title: "Components/Button",
  component: Button,
  argTypes: {
    variant: {
      control: { type: "select" },
      options: ["primary", "secondary", "ghost"]
    },
    size: {
      control: { type: "select" },
      options: ["small", "medium", "large"]
    }
  }
};

const Template = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = {
  children: "Primary Button",
  variant: "primary"
};

export const Secondary = Template.bind({});
Secondary.args = {
  children: "Secondary Button",
  variant: "secondary"
};
*/

// 7. Performance optimization
const MemoizedButton = React.memo(Button);
const MemoizedInput = React.memo(Input);

// 8. Theme hook
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within DesignSystemProvider");
  }
  return context;
}

// 9. Design tokens access
function useDesignToken(tokenPath) {
  const { theme } = useTheme();
  
  return tokenPath.split(".").reduce((obj, key) => obj?.[key], theme);
}

// Usage: const primaryColor = useDesignToken("colors.primary.500");

Answer: Design tokens for consistent styling Theme provider with light/dark mode Compound components for complex UIs Storybook for component documentation

DESIGN SYSTEM PATTERNS: Create consistent, reusable component libraries for large applications. KEY ELEMENTS: 1. DESIGN TOKENS: - Colors, typography, spacing - Breakpoints, shadows, borders - Semantic naming - Theme variations 2. COMPONENT LIBRARY: - Base components (Button, Input) - Complex components (Modal, DataTable) - Layout components (Grid, Container) - Compound components 3. DOCUMENTATION: - Storybook for component examples - Usage guidelines - Accessibility documentation - Code examples ARCHITECTURE PATTERNS: 1. THEME PROVIDER: - Context-based theming - Light/dark mode - Custom theme override - CSS-in-JS integration 2. COMPONENT API DESIGN: - Consistent prop naming - Compound components - Render props - Forward refs 3. STYLING APPROACHES: - CSS-in-JS (styled-components, Emotion) - CSS Modules - Utility-first (Tailwind) - BEM methodology PERFORMANCE OPTIMIZATIONS: 1. Component memoization 2. CSS extraction 3. Tree shaking 4. Code splitting 5. Lazy loading components ACCESSIBILITY FEATURES: 1. ARIA attributes 2. Keyboard navigation 3. Focus management 4. Screen reader support 5. Color contrast compliance TESTING STRATEGIES: 1. Visual regression testing 2. Component unit tests 3. Accessibility audits 4. Cross-browser testing 5. Performance testing VERSIONING & RELEASES: 1. Semantic versioning 2. Changelog 3. Breaking change management 4. Deprecation policies INTEGRATION PATTERNS: 1. NPM package 2. Monorepo 3. Module Federation 4. CDN distribution REAL-WORLD DESIGN SYSTEMS: 1. MATERIAL-UI: Google's design system 2. CHAKRA UI: Accessible components 3. ANT DESIGN: Enterprise design 4. CARBON: IBM design system 5. ATLASSIAN DESIGN SYSTEM: Jira, Confluence BEST PRACTICES: 1. Design tokens first 2. Accessibility by default 3. Consistent API 4. Comprehensive documentation 5. Performance monitoring TOOLING: 1. STORYBOOK: Component documentation 2. CHROMATIC: Visual testing 3. FIGMA: Design handoff 4. THEMING TOOLS: Style Dictionary ASKED AT: Meta, Google, Microsoft, Airbnb (design systems teams)

design-systemcomponent-librarystorybookaccessibility

28. Testing Strategies for React Applications

intermediate

Implement comprehensive testing: 1. Unit tests with Jest 2. Integration tests 3. E2E tests with Cypress 4. Testing hooks 5. Mocking strategies

javascript
// 1. Unit test for component
import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Counter from "./Counter";

describe("Counter", () => {
  it("renders initial count", () => {
    render(<Counter initialCount={5} />);
    expect(screen.getByText("Count: 5")).toBeInTheDocument();
  });
  
  it("increments count when increment button is clicked", async () => {
    render(<Counter initialCount={0} />);
    
    const incrementButton = screen.getByRole("button", { name: /increment/i });
    
    await userEvent.click(incrementButton);
    
    expect(screen.getByText("Count: 1")).toBeInTheDocument();
  });
  
  it("decrements count when decrement button is clicked", async () => {
    render(<Counter initialCount={10} />);
    
    const decrementButton = screen.getByRole("button", { name: /decrement/i });
    
    await userEvent.click(decrementButton);
    
    expect(screen.getByText("Count: 9")).toBeInTheDocument();
  });
  
  it("resets count when reset button is clicked", async () => {
    render(<Counter initialCount={20} />);
    
    const resetButton = screen.getByRole("button", { name: /reset/i });
    
    await userEvent.click(resetButton);
    
    expect(screen.getByText("Count: 0")).toBeInTheDocument();
  });
  
  it("calls onChange callback when count changes", () => {
    const handleChange = jest.fn();
    render(<Counter initialCount={0} onChange={handleChange} />);
    
    fireEvent.click(screen.getByText("Increment"));
    
    expect(handleChange).toHaveBeenCalledWith(1);
  });
});

// 2. Testing custom hook
import { renderHook, act } from "@testing-library/react";
import { useCounter } from "./useCounter";

describe("useCounter", () => {
  it("should use initial value", () => {
    const { result } = renderHook(() => useCounter(5));
    
    expect(result.current.count).toBe(5);
  });
  
  it("should increment", () => {
    const { result } = renderHook(() => useCounter(0));
    
    act(() => {
      result.current.increment();
    });
    
    expect(result.current.count).toBe(1);
  });
  
  it("should decrement", () => {
    const { result } = renderHook(() => useCounter(10));
    
    act(() => {
      result.current.decrement();
    });
    
    expect(result.current.count).toBe(9);
  });
  
  it("should reset", () => {
    const { result } = renderHook(() => useCounter(20));
    
    act(() => {
      result.current.increment();
      result.current.reset();
    });
    
    expect(result.current.count).toBe(0);
  });
  
  it("should not go below min", () => {
    const { result } = renderHook(() => useCounter(0, { min: 0 }));
    
    act(() => {
      result.current.decrement();
    });
    
    expect(result.current.count).toBe(0);
  });
});

// 3. Integration test for form
import { waitFor } from "@testing-library/react";
import LoginForm from "./LoginForm";
import { login } from "./api";

jest.mock("./api");

describe("LoginForm", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });
  
  it("submits form with valid data", async () => {
    const mockLogin = login.mockResolvedValue({ success: true });
    const onSuccess = jest.fn();
    
    render(<LoginForm onSuccess={onSuccess} />);
    
    const emailInput = screen.getByLabelText(/email/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /login/i });
    
    // Fill form
    await userEvent.type(emailInput, "test@example.com");
    await userEvent.type(passwordInput, "password123");
    
    // Submit
    await userEvent.click(submitButton);
    
    // Check API call
    expect(mockLogin).toHaveBeenCalledWith({
      email: "test@example.com",
      password: "password123"
    });
    
    // Check success callback
    await waitFor(() => {
      expect(onSuccess).toHaveBeenCalled();
    });
  });
  
  it("shows error on failed login", async () => {
    login.mockRejectedValue(new Error("Invalid credentials"));
    
    render(<LoginForm />);
    
    const emailInput = screen.getByLabelText(/email/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const submitButton = screen.getByRole("button", { name: /login/i });
    
    // Fill form
    await userEvent.type(emailInput, "wrong@example.com");
    await userEvent.type(passwordInput, "wrong");
    
    // Submit
    await userEvent.click(submitButton);
    
    // Check error message
    await waitFor(() => {
      expect(screen.getByText(/invalid credentials/i)).toBeInTheDocument();
    });
  });
  
  it("validates required fields", async () => {
    render(<LoginForm />);
    
    const submitButton = screen.getByRole("button", { name: /login/i });
    
    await userEvent.click(submitButton);
    
    expect(screen.getByText(/email is required/i)).toBeInTheDocument();
    expect(screen.getByText(/password is required/i)).toBeInTheDocument();
    
    expect(login).not.toHaveBeenCalled();
  });
});

// 4. Mocking strategies
// Mock module
export const mockApi = {
  fetchUser: jest.fn(),
  updateUser: jest.fn(),
  deleteUser: jest.fn()
};

jest.mock("./api", () => mockApi);

// Mock window properties
beforeAll(() => {
  Object.defineProperty(window, "matchMedia", {
    writable: true,
    value: jest.fn().mockImplementation(query => ({
      matches: false,
      media: query,
      onchange: null,
      addListener: jest.fn(),
      removeListener: jest.fn(),
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn()
    }))
  });
});

// Mock router
import { MemoryRouter } from "react-router-dom";

describe("App with router", () => {
  it("navigates to about page", async () => {
    render(
      <MemoryRouter initialEntries={["/about"]}>
        <App />
      </MemoryRouter>
    );
    
    expect(screen.getByText(/about page/i)).toBeInTheDocument();
  });
});

// Mock context
const mockAuthContext = {
  user: { name: "Test User" },
  login: jest.fn(),
  logout: jest.fn()
};

jest.mock("./AuthContext", () => ({
  useAuth: () => mockAuthContext
}));

// 5. E2E test with Cypress
/*
// login.spec.cy.js
describe("Login", () => {
  beforeEach(() => {
    cy.visit("/login");
  });
  
  it("should login with valid credentials", () => {
    cy.intercept("POST", "/api/login", {
      statusCode: 200,
      body: { user: { name: "John Doe" } }
    }).as("loginRequest");
    
    cy.get("[data-testid=email]").type("test@example.com");
    cy.get("[data-testid=password]").type("password123");
    cy.get("[data-testid=login-button]").click();
    
    cy.wait("@loginRequest");
    cy.url().should("include", "/dashboard");
    cy.contains("Welcome, John Doe").should("be.visible");
  });
  
  it("should show error with invalid credentials", () => {
    cy.intercept("POST", "/api/login", {
      statusCode: 401,
      body: { error: "Invalid credentials" }
    }).as("loginRequest");
    
    cy.get("[data-testid=email]").type("wrong@example.com");
    cy.get("[data-testid=password]").type("wrong");
    cy.get("[data-testid=login-button]").click();
    
    cy.wait("@loginRequest");
    cy.contains("Invalid credentials").should("be.visible");
  });
});
*/

// 6. Snapshot testing
it("renders correctly", () => {
  const { asFragment } = render(<Button>Click me</Button>);
  expect(asFragment()).toMatchSnapshot();
});

// 7. Performance testing
import { measurePerformance } from "reassure";

test("Button render performance", async () => {
  await measurePerformance(<Button>Click me</Button>);
});

// 8. Accessibility testing
import { axe } from "jest-axe";

it("should have no accessibility violations", async () => {
  const { container } = render(<Button>Accessible button</Button>);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

// 9. Test coverage configuration
/*
// jest.config.js
module.exports = {
  collectCoverageFrom: [
    "src/**/*.{js,jsx,ts,tsx}",
    "!src/**/*.d.ts",
    "!src/index.js",
    "!src/reportWebVitals.js"
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  }
};
*/

// 10. CI/CD test configuration
/*
// .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: "18"
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run unit tests
        run: npm test -- --coverage
      
      - name: Run integration tests
        run: npm run test:integration
      
      - name: Run E2E tests
        run: npm run test:e2e
        env:
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
*/

// 11. Mock server for testing
import { setupServer } from "msw/node";
import { rest } from "msw";

const server = setupServer(
  rest.get("/api/user", (req, res, ctx) => {
    return res(
      ctx.json({ name: "John Doe" })
    );
  }),
  
  rest.post("/api/login", (req, res, ctx) => {
    return res(
      ctx.json({ token: "fake-token" })
    );
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Answer: Unit tests with Jest and React Testing Library Integration tests for user flows E2E tests with Cypress Mocking APIs and dependencies

TESTING STRATEGIES FOR REACT: Comprehensive testing pyramid for React applications. TESTING PYRAMID: 1. UNIT TESTS (60-70%): - Test individual components - Test custom hooks - Test utility functions - Fast, isolated tests 2. INTEGRATION TESTS (20-30%): - Test component interactions - Test user flows - Test with context/providers - Test API integrations 3. E2E TESTS (10%): - Test complete user journeys - Test across multiple pages - Test in real browser - Slow but realistic TOOLING: 1. UNIT TESTING: - Jest: Test runner - React Testing Library: Component testing - @testing-library/user-event: User interactions 2. INTEGRATION TESTING: - Same as unit + MSW for API mocking - Jest DOM for assertions - React Testing Library for rendering 3. E2E TESTING: - Cypress: Modern E2E - Playwright: Cross-browser - Selenium: Legacy MOCKING STRATEGIES: 1. API MOCKS: - MSW (Mock Service Worker) - Jest mock functions - Fetch/axios interceptors 2. CONTEXT MOCKS: - Mock React context - Mock Redux store - Mock Router 3. WINDOW MOCKS: - localStorage/sessionStorage - matchMedia - IntersectionObserver - ResizeObserver TESTING PATTERNS: 1. COMPONENT TESTS: - Render assertions - User interactions - Props testing - Event handlers 2. HOOK TESTS: - renderHook from RTL - act for state updates - Async hook testing 3. FORM TESTS: - Form submission - Validation errors - Field interactions 4. ASYNC TESTS: - waitFor for async updates - Mock timers - Loading states PERFORMANCE TESTING: 1. REASSURE: Performance regression 2. LIGHTHOUSE CI: Performance scores 3. WEB VITALS: Core web vitals ACCESSIBILITY TESTING: 1. JEST-AXE: Accessibility violations 2. LIGHTHOUSE: Accessibility audits 3. MANUAL: Screen reader testing COVERAGE METRICS: 1. Line coverage 2. Branch coverage 3. Function coverage 4. Statement coverage BEST PRACTICES: 1. Test behavior, not implementation 2. Use data-testid sparingly 3. Prefer userEvent over fireEvent 4. Clean up after tests 5. Run tests in CI/CD TEST ORGANIZATION: 1. Arrange-Act-Assert pattern 2. Descriptive test names 3. Shared test utilities 4. Test fixtures DEBUGGING: 1. screen.debug() 2. Jest --verbose 3. Cypress test runner 4. React DevTools ASKED AT: Meta, Google, Netflix (testing-focused roles)

testingjestcypressreact-testing-library

29. Performance Monitoring and Optimization

advanced

Implement performance monitoring: 1. Web Vitals tracking 2. Bundle analysis 3. React Profiler integration 4. Custom performance metrics 5. Real User Monitoring (RUM)

javascript
// 1. Web Vitals tracking
import { getCLS, getFID, getLCP, getFCP, getTTFB } from "web-vitals";

function sendToAnalytics(metric) {
  const body = {
    name: metric.name,
    value: metric.value,
    rating: metric.rating,
    delta: metric.delta,
    id: metric.id,
    navigationType: metric.navigationType
  };
  
  // Send to your analytics
  fetch("/api/analytics/web-vitals", {
    method: "POST",
    body: JSON.stringify(body),
    headers: { "Content-Type": "application/json" }
  });
  
  // Log to console in development
  if (process.env.NODE_ENV === "development") {
    console.log(metric);
  }
}

// Initialize web vitals tracking
function initWebVitals() {
  if (typeof window === "undefined") return;
  
  getCLS(sendToAnalytics);
  getFID(sendToAnalytics);
  getLCP(sendToAnalytics);
  getFCP(sendToAnalytics);
  getTTFB(sendToAnalytics);
}

// 2. React Profiler integration
function ProfilerWrapper({ children, id }) {
  const handleRender = useCallback(
    (id, phase, actualDuration, baseDuration, startTime, commitTime) => {
      // Performance logging
      console.log(`Profiler [${id}]:`, {
        phase,
        actualDuration,
        baseDuration,
        startTime,
        commitTime,
        commitTime - startTime
      });
      
      // Send to analytics for production
      if (process.env.NODE_ENV === "production") {
        const metric = {
          componentId: id,
          phase,
          duration: actualDuration,
          timestamp: Date.now()
        };
        
        // Queue for batch sending
        performanceMetricsQueue.push(metric);
      }
    },
    []
  );
  
  return (
    <React.Profiler id={id} onRender={handleRender}>
      {children}
    </React.Profiler>
  );
}

// 3. Custom performance metrics
class PerformanceMonitor {
  constructor() {
    this.metrics = new Map();
    this.observers = [];
  }
  
  // Start measurement
  start(metricName) {
    if (this.metrics.has(metricName)) {
      console.warn(`Metric "${metricName}" already started`);
      return;
    }
    
    this.metrics.set(metricName, {
      startTime: performance.now(),
      marks: []
    });
  }
  
  // Mark a point in time
  mark(metricName, markName) {
    const metric = this.metrics.get(metricName);
    if (!metric) {
      console.warn(`Metric "${metricName}" not found`);
      return;
    }
    
    metric.marks.push({
      name: markName,
      time: performance.now() - metric.startTime
    });
  }
  
  // End measurement
  end(metricName) {
    const metric = this.metrics.get(metricName);
    if (!metric) {
      console.warn(`Metric "${metricName}" not found`);
      return;
    }
    
    const endTime = performance.now();
    const duration = endTime - metric.startTime;
    
    // Notify observers
    this.observers.forEach(observer => {
      observer({
        name: metricName,
        duration,
        marks: metric.marks,
        startTime: metric.startTime,
        endTime
      });
    });
    
    // Remove from metrics
    this.metrics.delete(metricName);
    
    return duration;
  }
  
  // Add observer
  observe(callback) {
    this.observers.push(callback);
    return () => {
      const index = this.observers.indexOf(callback);
      if (index > -1) this.observers.splice(index, 1);
    };
  }
}

// Singleton instance
export const perfMonitor = new PerformanceMonitor();

// 4. Hook for measuring component render time
function useRenderTime(componentName) {
  const startTime = useRef(performance.now());
  
  useEffect(() => {
    const renderTime = performance.now() - startTime.current;
    
    // Log render time
    if (process.env.NODE_ENV === "development") {
      console.log(`[${componentName}] Render time:`, renderTime.toFixed(2), "ms");
    }
    
    // Send to analytics if too slow
    if (renderTime > 100) { // 100ms threshold
      perfMonitor.end(`${componentName}_render`);
    }
  });
}

// 5. Bundle analysis plugin
function BundleAnalyzer() {
  useEffect(() => {
    if (process.env.NODE_ENV === "development") {
      import("webpack-bundle-analyzer").then(({ BundleAnalyzerPlugin }) => {
        // Could trigger analysis
      });
    }
  }, []);
  
  return null;
}

// 6. Real User Monitoring (RUM) setup
class RUMTracker {
  constructor() {
    this.sessionId = this.generateSessionId();
    this.pageLoadTime = null;
    this.resourceTimings = [];
    
    this.init();
  }
  
  generateSessionId() {
    return "session_" + Math.random().toString(36).substr(2, 9);
  }
  
  init() {
    // Track page load
    window.addEventListener("load", () => {
      this.pageLoadTime = performance.now();
      this.trackPageLoad();
    });
    
    // Track resource timings
    if (performance.getEntriesByType) {
      const resources = performance.getEntriesByType("resource");
      this.resourceTimings = resources.map(resource => ({
        name: resource.name,
        duration: resource.duration,
        initiatorType: resource.initiatorType,
        transferSize: resource.transferSize
      }));
    }
    
    // Track errors
    window.addEventListener("error", this.trackError.bind(this));
    
    // Track unhandled rejections
    window.addEventListener("unhandledrejection", this.trackPromiseError.bind(this));
  }
  
  trackPageLoad() {
    const timing = performance.timing;
    const metrics = {
      sessionId: this.sessionId,
      page: window.location.pathname,
      dns: timing.domainLookupEnd - timing.domainLookupStart,
      tcp: timing.connectEnd - timing.connectStart,
      request: timing.responseStart - timing.requestStart,
      response: timing.responseEnd - timing.responseStart,
      domInteractive: timing.domInteractive - timing.navigationStart,
      domComplete: timing.domComplete - timing.navigationStart,
      loadEvent: timing.loadEventEnd - timing.navigationStart,
      firstPaint: performance.getEntriesByName("first-paint")[0]?.startTime,
      firstContentfulPaint: performance.getEntriesByName("first-contentful-paint")[0]?.startTime
    };
    
    this.sendToBackend("page-load", metrics);
  }
  
  trackError(event) {
    const errorData = {
      sessionId: this.sessionId,
      message: event.message,
      filename: event.filename,
      lineno: event.lineno,
      colno: event.colno,
      error: event.error?.stack
    };
    
    this.sendToBackend("error", errorData);
  }
  
  trackPromiseError(event) {
    const errorData = {
      sessionId: this.sessionId,
      reason: event.reason,
      promise: event.promise
    };
    
    this.sendToBackend("promise-error", errorData);
  }
  
  sendToBackend(type, data) {
    // Use Beacon API for reliability
    const blob = new Blob([JSON.stringify({
      type,
      data,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      viewport: `${window.innerWidth}x${window.innerHeight}`
    })], { type: "application/json" });
    
    navigator.sendBeacon("/api/rum", blob);
  }
}

// Initialize RUM
if (typeof window !== "undefined") {
  window.__RUM = new RUMTracker();
}

// 7. Performance optimization hook
function usePerformanceOptimization() {
  const [isSlowConnection, setIsSlowConnection] = useState(false);
  
  useEffect(() => {
    // Check connection speed
    const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
    
    if (connection) {
      const handleChange = () => {
        const isSlow = connection.saveData || 
          connection.effectiveType === "slow-2g" || 
          connection.effectiveType === "2g";
        
        setIsSlowConnection(isSlow);
        
        // Emit event for other components
        window.dispatchEvent(new CustomEvent("connection-change", {
          detail: { isSlow }
        }));
      };
      
      connection.addEventListener("change", handleChange);
      handleChange(); // Initial check
      
      return () => connection.removeEventListener("change", handleChange);
    }
  }, []);
  
  return { isSlowConnection };
}

// 8. Lazy loading based on connection
function AdaptiveComponent({ fullComponent, lightComponent, fallback }) {
  const { isSlowConnection } = usePerformanceOptimization();
  
  const Component = isSlowConnection ? lightComponent : fullComponent;
  const LazyComponent = React.lazy(() => 
    isSlowConnection 
      ? import(`./${lightComponent}`)
      : import(`./${fullComponent}`)
  );
  
  return (
    <Suspense fallback={fallback}>
      <LazyComponent />
    </Suspense>
  );
}

// 9. Memory leak detection
function useMemoryLeakDetection(componentName) {
  useEffect(() => {
    const initialMemory = performance.memory?.usedJSHeapSize;
    
    return () => {
      // Check memory on unmount
      setTimeout(() => {
        const currentMemory = performance.memory?.usedJSHeapSize;
        if (currentMemory && initialMemory) {
          const diff = currentMemory - initialMemory;
          if (diff > 10 * 1024 * 1024) { // 10MB threshold
            console.warn(`Potential memory leak in ${componentName}: +${(diff / 1024 / 1024).toFixed(2)}MB`);
          }
        }
      }, 1000);
    };
  }, [componentName]);
}

// 10. Performance budget monitoring
const performanceBudget = {
  bundleSize: 200 * 1024, // 200KB
  firstContentfulPaint: 1800, // 1.8s
  largestContentfulPaint: 2500, // 2.5s
  cumulativeLayoutShift: 0.1,
  timeToInteractive: 3800 // 3.8s
};

function checkPerformanceBudget(metrics) {
  const violations = [];
  
  if (metrics.fcp > performanceBudget.firstContentfulPaint) {
    violations.push(`FCP: ${metrics.fcp}ms > ${performanceBudget.firstContentfulPaint}ms`);
  }
  
  if (metrics.lcp > performanceBudget.largestContentfulPaint) {
    violations.push(`LCP: ${metrics.lcp}ms > ${performanceBudget.largestContentfulPaint}ms`);
  }
  
  if (metrics.cls > performanceBudget.cumulativeLayoutShift) {
    violations.push(`CLS: ${metrics.cls} > ${performanceBudget.cumulativeLayoutShift}`);
  }
  
  if (violations.length > 0) {
    console.warn("Performance budget violations:", violations);
    // Send to monitoring service
    sendToMonitoringService({
      type: "performance-budget-violation",
      violations
    });
  }
}

Answer: Web Vitals tracking for Core Web Vitals React Profiler for component performance Real User Monitoring (RUM) for production Performance budgets and optimization

PERFORMANCE MONITORING PATTERNS: Measure and optimize React application performance. KEY METRICS: 1. CORE WEB VITALS: - LCP (Largest Contentful Paint): Loading performance - FID (First Input Delay): Interactivity - CLS (Cumulative Layout Shift): Visual stability 2. REACT-SPECIFIC METRICS: - Component render time - Re-render count - Bundle size - Memory usage MONITORING STRATEGIES: 1. SYNTHETIC MONITORING: - Lab testing - Lighthouse - WebPageTest - Build-time checks 2. REAL USER MONITORING (RUM): - Production performance - User experience - Error tracking - Business metrics TOOLING: 1. GOOGLE TOOLS: - Lighthouse: Auditing - PageSpeed Insights: Recommendations - Search Console: Field data 2. COMMERCIAL TOOLS: - New Relic: Full-stack APM - Datadog: Performance monitoring - Sentry: Error tracking 3. SELF-HOSTED: - Prometheus + Grafana - Elastic APM - OpenTelemetry REACT-SPECIFIC OPTIMIZATIONS: 1. BUNDLE OPTIMIZATION: - Code splitting - Tree shaking - Compression - CDN caching 2. RENDER OPTIMIZATION: - Memoization - Virtualization - Lazy loading - Concurrent features 3. NETWORK OPTIMIZATION: - HTTP/2 - Brotli compression - Image optimization - Service workers PERFORMANCE BUDGETS: 1. Bundle size limits 2. Time-based thresholds 3. Score-based targets 4. User-centric metrics IMPLEMENTATION PATTERNS: 1. MEASUREMENT: - Performance API - React Profiler - Custom timers 2. REPORTING: - Analytics integration - Alerting - Dashboards 3. OPTIMIZATION: - A/B testing - Progressive enhancement - Adaptive loading BEST PRACTICES: 1. Measure before optimizing 2. Set realistic budgets 3. Monitor trends, not absolutes 4. Focus on user experience 5. Test on real devices ERROR MONITORING: 1. JavaScript errors 2. Network failures 3. Resource loading errors 4. Promise rejections BUSINESS METRICS CORRELATION: 1. Conversion rates vs performance 2. User engagement vs speed 3. Revenue impact 4. SEO rankings CONTINUOUS MONITORING: 1. CI/CD integration 2. Automated alerts 3. Performance regression testing 4. Canary analysis ASKED AT: Google, Meta, Netflix (performance engineering)

performancemonitoringweb-vitalsoptimization