FrontendDeveloper.in

React Interview Questions

  • Question 316

    5. **Concurrency and Prioritization**

    • React can prepare multiple versions of UI at once (e.g., during slow data loading).
    • Updates can be assigned priorities, so urgent updates (like clicks) are handled faster than background work.
  • Question 317

    What is the useId hook and when should you use it?

    The useId hook is a React hook introduced in React 18 that generates unique IDs that are stable across server and client renders. It's primarily used for accessibility attributes like linking form labels to inputs.

    Syntax

    const id = useId();
    

    Example: Accessible Form Input

    import { useId } from 'react';
    
    function EmailField() {
    const id = useId();
    
    return (
    <label htmlFor={id}>Email:</label>
    <input id={id} type="email" />
    );
    }
    

    When to Use

    • Generating unique IDs for form elements (htmlFor, aria-describedby, aria-labelledby)
    • Creating stable IDs in server-side rendering (SSR) applications
    • Avoiding ID collisions when the same component is rendered multiple times

    When NOT to Use

    • As keys in a list (use data-based keys instead)
    • As CSS selectors or query selectors
    • For any purpose that requires the ID to be predictable

    Note: The IDs generated by useId contain colons (:) which may not work in CSS selectors. For multiple related IDs, you can use the same id as a prefix: ${id}-firstName, ${id}-lastName.

  • Question 318

    What is the useDeferredValue hook?

    The useDeferredValue hook is used to defer updating a part of the UI to keep other parts responsive. It accepts a value and returns a "deferred" version of that value that may lag behind. This is useful for optimizing performance when rendering expensive components.

    Syntax

    const deferredValue = useDeferredValue(value);
    

    Example: Search with Deferred Results

    import { useState, useDeferredValue, useMemo } from 'react';
    
    function SearchResults({ query }) {
    // Expensive computation or large list filtering
    const results = useMemo(() => {
    return largeDataSet.filter(item =>
    item.name.toLowerCase().includes(query.toLowerCase())
    );
    }, [query]);
    
    return (
    <ul>
    {results.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
    );
    }
    
    function SearchPage() {
    const [query, setQuery] = useState('');
    const deferredQuery = useDeferredValue(query);
    const isStale = query !== deferredQuery;
    
    return (
    <input
    value={query}
    onChange={(e) => setQuery(e.target.value)}
    placeholder="Search..."
    />
    <SearchResults query={deferredQuery} />
    );
    }
    

    The input stays responsive while the expensive SearchResults component re-renders with a slight delay using the deferred value.

  • Question 319

    What is the useTransition hook and how does it differ from useDeferredValue?

    The useTransition hook allows you to mark certain state updates as non-urgent transitions, keeping the UI responsive during expensive re-renders. It returns a isPending flag and a startTransition function.

    Syntax

    const [isPending, startTransition] = useTransition();
    

    Example: Tab Switching

    import { useState, useTransition } from 'react';
    
    function TabContainer() {
    const [isPending, startTransition] = useTransition();
    const [tab, setTab] = useState('home');
    
    function selectTab(nextTab) {
    startTransition(() => {
    setTab(nextTab);
    });
    }
    
    return (
    <button onClick={() => selectTab('home')}>Home</button>
    <button onClick={() => selectTab('posts')}>Posts (slow)</button>
    <button onClick={() => selectTab('contact')}>Contact</button>
    
    {isPending && <Spinner />}
    
    {tab === 'home' && <HomeTab />}
    {tab === 'posts' && <PostsTab />}  {/* Expensive component */}
    {tab === 'contact' && <ContactTab />}
    );
    }
    

    Differences from useDeferredValue

    FeatureuseTransitionuseDeferredValue
    ControlsState updates (wraps setState)Values (wraps a value)
    Use caseWhen you control the state updateWhen you receive a value from props or other hooks
    Returns[isPending, startTransition]Deferred value
    Pending stateBuilt-in isPending flagManual comparison needed
  • Question 320

    What is the useSyncExternalStore hook?

    The useSyncExternalStore hook is designed to subscribe to external stores (non-React state sources) in a way that's compatible with concurrent rendering. It's primarily used by library authors for state management libraries.

    Syntax

    const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?);
    
    • subscribe: Function to subscribe to the store, returns an unsubscribe function
    • getSnapshot: Function that returns the current store value
    • getServerSnapshot: Optional function for SSR that returns the initial server snapshot

    Example: Browser Online Status

    import { useSyncExternalStore } from 'react';
    
    function getSnapshot() {
    return navigator.onLine;
    }
    
    function subscribe(callback) {
    window.addEventListener('online', callback);
    window.addEventListener('offline', callback);
    return () => {
    window.removeEventListener('online', callback);
    window.removeEventListener('offline', callback);
    };
    }
    
    function useOnlineStatus() {
    return useSyncExternalStore(subscribe, getSnapshot, () => true);
    }
    
    function StatusBar() {
    const isOnline = useOnlineStatus();
    return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
    }
    

    This hook ensures that when the external store changes, React re-renders consistently without tearing (showing inconsistent data).

  • Question 321

    What is the useInsertionEffect hook?

    The useInsertionEffect hook is designed for CSS-in-JS library authors to inject styles into the DOM before any layout effects run. It fires synchronously before DOM mutations.

    Syntax

    useInsertionEffect(() => {
    // Insert styles here
    return () => {
    // Cleanup
    };
    }, [dependencies]);
    

    Execution Order

    1. useInsertionEffect  → Inject styles
    2. DOM mutations       → React updates DOM
    3. useLayoutEffect     → Read layout, synchronously re-render if needed
    4. Browser paint       → User sees the result
    5. useEffect           → Side effects run
    

    Example: Dynamic Style Injection

    import { useInsertionEffect } from 'react';
    
    let isInserted = new Set();
    
    function useCSS(rule) {
    useInsertionEffect(() => {
    if (!isInserted.has(rule)) {
    isInserted.add(rule);
    const style = document.createElement('style');
    style.textContent = rule;
    document.head.appendChild(style);
    }
    }, [rule]);
    }
    
    function Button() {
    useCSS('.dynamic-btn { background: blue; color: white; }');
    return <button className="dynamic-btn">Click me</button>;
    }
    

    Note: This hook is not intended for application code. It's specifically for CSS-in-JS libraries like styled-components or Emotion to prevent style flickering.

  • Question 322

    How do you share state logic between components using custom hooks?

    Custom hooks allow you to extract and share stateful logic between components without changing their hierarchy. The state itself is not shared—each component using the hook gets its own isolated state.

    Example: useLocalStorage Hook

    import { useState, useEffect } from 'react';
    
    function useLocalStorage(key, initialValue) {
    // Get stored value or use initial value
    const [storedValue, setStoredValue] = useState(() => {
    try {
    const item = window.localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
    } catch (error) {
    console.error(error);
    return initialValue;
    }
    });
    
    // Update localStorage when state changes
    useEffect(() => {
    try {
    window.localStorage.setItem(key, JSON.stringify(storedValue));
    } catch (error) {
    console.error(error);
    }
    }, [key, storedValue]);
    
    return [storedValue, setStoredValue];
    }
    
    // Usage in multiple components
    function ThemeToggle() {
    const [theme, setTheme] = useLocalStorage('theme', 'light');
    return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
    Current: {theme}
    </button>
    );
    }
    
    function FontSizeSelector() {
    const [fontSize, setFontSize] = useLocalStorage('fontSize', 16);
    return (
    <input
    type="range"
    value={fontSize}
    onChange={(e) => setFontSize(Number(e.target.value))}
    />
    );
    }
    

    Both components use useLocalStorage, but each has its own independent state that persists to localStorage.

  • Question 323

    What is the useDebugValue hook?

    The useDebugValue hook is used to display a label for custom hooks in React DevTools. It helps developers debug custom hooks by showing meaningful information.

    Syntax

    useDebugValue(value);
    useDebugValue(value, formatFn); // With optional formatter
    

    Example: Custom Hook with Debug Value

    import { useState, useEffect, useDebugValue } from 'react';
    
    function useOnlineStatus() {
    const [isOnline, setIsOnline] = useState(true);
    
    useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);
    
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    
    return () => {
    window.removeEventListener('online', handleOnline);
    window.removeEventListener('offline', handleOffline);
    };
    }, []);
    
    // Shows "OnlineStatus: Online" or "OnlineStatus: Offline" in DevTools
    useDebugValue(isOnline ? 'Online' : 'Offline');
    
    return isOnline;
    }
    

    With Formatting Function (for expensive computations)

    function useUser(userId) {
    const [user, setUser] = useState(null);
    
    // The format function only runs when DevTools is open
    useDebugValue(user, (user) => user ? `User: ${user.name}` : 'Loading...');
    
    return user;
    }
    

    Note: Only use useDebugValue in custom hooks that are part of shared libraries. It's not necessary for every custom hook in application code.

  • Question 324

    How do you handle cleanup in useEffect?

    The cleanup function in useEffect is used to clean up side effects before the component unmounts or before the effect runs again. This prevents memory leaks, stale data, and unexpected behavior.

    Syntax

    useEffect(() => {
    // Setup code
    
    return () => {
    // Cleanup code
    };
    }, [dependencies]);
    

    Common Cleanup Scenarios

    1. Event Listeners

    useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    
    return () => window.removeEventListener('resize', handleResize);
    }, []);
    

    2. Timers and Intervals

    useEffect(() => {
    const intervalId = setInterval(() => {
    setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(intervalId);
    }, []);
    

    3. Subscriptions

    useEffect(() => {
    const subscription = dataSource.subscribe(handleChange);
    
    return () => subscription.unsubscribe();
    }, [dataSource]);
    

    4. Abort Fetch Requests

    useEffect(() => {
    const controller = new AbortController();
    
    fetch(url, { signal: controller.signal })
    .then(response => response.json())
    .then(data => setData(data))
    .catch(err => {
    if (err.name !== 'AbortError') {
    setError(err);
    }
    });
    
    return () => controller.abort();
    }, [url]);
    

    When Cleanup Runs:

    • Before the component unmounts
    • Before re-running the effect when dependencies change
  • Question 325

    What are the differences between useEffect and useEvent (experimental)?

    useEvent is an experimental hook (not yet stable in React) designed to solve the problem of creating stable event handlers that always access the latest props and state without causing re-renders or needing to be in dependency arrays.

    The Problem useEvent Solves

    // Problem: onTick changes on every render, causing interval to reset
    function Timer({ onTick }) {
    useEffect(() => {
    const id = setInterval(() => {
    onTick(); // Uses stale closure if onTick is not in deps
    }, 1000);
    return () => clearInterval(id);
    }, [onTick]); // Adding onTick causes interval to reset frequently
    }
    

    Solution with useEvent (Experimental)

    import { useEvent } from 'react'; // Experimental
    
    function Timer({ onTick }) {
    const stableOnTick = useEvent(onTick);
    
    useEffect(() => {
    const id = setInterval(() => {
    stableOnTick(); // Always calls latest onTick
    }, 1000);
    return () => clearInterval(id);
    }, []); // No dependency needed!
    }
    

    Key Differences

    FeatureuseEffectuseEvent (experimental)
    PurposeRun side effectsCreate stable callbacks
    RunsAfter renderDuring render (creates function)
    ReturnsCleanup functionStable event handler
    ClosureCaptures values at render timeAlways accesses latest values
    DependenciesMust list all used valuesNot needed in other hooks' deps

    Note: Until useEvent is stable, you can use useCallback with useRef as a workaround for stable callbacks.

  • Question 326

    What are the best practices for using React Hooks?

    Following best practices ensures your hooks are predictable, maintainable, and bug-free.

    1. Follow the Rules of Hooks

    • Only call hooks at the top level (not inside loops, conditions, or nested functions)
    • Only call hooks from React functions (components or custom hooks)

    2. Use the ESLint Plugin

    npm install eslint-plugin-react-hooks --save-dev
    
    {
    "plugins": ["react-hooks"],
    "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
    }
    }
    

    3. Keep Hooks Focused and Simple

    // ❌ Bad: One hook doing too much
    function useEverything() {
    const [user, setUser] = useState(null);
    const [posts, setPosts] = useState([]);
    const [theme, setTheme] = useState('light');
    // ... lots of unrelated logic
    }
    
    // ✅ Good: Separate concerns
    function useUser() { /* user logic */ }
    function usePosts() { /* posts logic */ }
    function useTheme() { /* theme logic */ }
    

    4. Use Descriptive Names for Custom Hooks

    // ❌ Bad
    function useData() { }
    
    // ✅ Good
    function useUserAuthentication() { }
    function useFetchProducts() { }
    function useFormValidation() { }
    

    5. Properly Manage Dependencies

    // ❌ Bad: Missing dependency
    useEffect(() => {
    fetchUser(userId);
    }, []); // userId is missing
    
    // ✅ Good: All dependencies listed
    useEffect(() => {
    fetchUser(userId);
    }, [userId]);
    

    6. Avoid Inline Object/Function Dependencies

    // ❌ Bad: New object on every render
    useEffect(() => {
    doSomething(options);
    }, [{ page: 1, limit: 10 }]); // Always different reference
    
    // ✅ Good: Memoize or extract
    const options = useMemo(() => ({ page: 1, limit: 10 }), []);
    useEffect(() => {
    doSomething(options);
    }, [options]);
    

    7. Clean Up Side Effects

    Always return a cleanup function when subscribing to events, timers, or external data sources.

    Old Q&A

  • Question 327

    Why should we not update the state directly?

    If you try to update the state directly then it won't re-render the component.

    //Wrong
    this.state.message = "Hello world";
    

    Instead use setState() method. It schedules an update to a component's state object. When state changes, the component responds by re-rendering.

    //Correct
    this.setState({ message: "Hello World" });
    

    Note: You can directly assign to the state object either in constructor or using latest javascript's class field declaration syntax.

  • Question 328

    What is the purpose of callback function as an argument of `setState()`?

    The callback function provided as the second argument to setState is executed after the state has been updated and the component has re-rendered. Because setState() is asynchronous, you cannot reliably perform actions that require the updated state immediately after calling setState. The callback ensures your code runs only after the update and re-render are complete.

    Example

    this.setState({ name: "Sudheer" }, () => {
    console.log("The name has been updated and the component has re-rendered.");
    });
    

    When to use the callback?

    Use the setState callback when you need to perform an action immediately after the DOM has been updated in response to a state change. i.e, The callback is a reliable way to perform actions after a state update and re-render, especially when the timing is critical due to the asynchronous nature of state updates in React. For example, if you need to interact with the updated DOM, trigger analytics, or perform further computations that depend on the new state or rendered output.

    Note

    • In modern React (with function components), you can achieve similar effects using the useEffect hook to respond to state changes.
    • In class components, you can also use lifecycle methods like componentDidUpdate for broader post-update logic.
    • The setState callback is still useful for one-off actions that directly follow a specific state change.
  • Question 329

    How to bind methods or event handlers in JSX callbacks?

    There are 3 possible ways to achieve this in class components:

    1. Binding in Constructor: In JavaScript classes, the methods are not bound by default. The same rule applies for React event handlers defined as class methods. Normally we bind them in constructor.
    class User extends Component {
    constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
    console.log("SingOut triggered");
    }
    render() {
    return <button onClick={this.handleClick}>SingOut</button>;
    }
    }
    
    1. Public class fields syntax: If you don't like to use bind approach then public class fields syntax can be used to correctly bind callbacks. The Create React App enables this syntax by default.
    handleClick = () => {
    console.log("SingOut triggered", this);
    };
    
    <button onClick={this.handleClick}>SingOut</button>
    
    1. Arrow functions in callbacks: It is possible to use arrow functions directly in the callbacks.
    handleClick() {
    console.log('SingOut triggered');
    }
    render() {
    return <button onClick={() => this.handleClick()}>SignOut</button>;
    }
    

    Note: If the callback is passed as prop to child components, those components might do an extra re-rendering. In those cases, it is preferred to go with .bind() or public class fields syntax approach considering performance.

  • Question 330

    How to pass a parameter to an event handler or callback?

    You can use an arrow function to wrap around an event handler and pass parameters:

    <button onClick={() => this.handleClick(id)} />
    

    This is an equivalent to calling .bind:

    <button onClick={this.handleClick.bind(this, id)} />
    

    Apart from these two approaches, you can also pass arguments to a function which is defined as arrow function

    <button onClick={this.handleClick(id)} />;
    handleClick = (id) => () => {
    console.log("Hello, your ticket number is", id);
    };
    
Get LinkedIn Premium at Rs 399