React Interview Questions and Answers

Find 100+ React interview questions and answers to assess candidates' skills in ReactJS, hooks, state management, and performance. Hire top React developers easily!
By
WeCP Team

As React continues to dominate the front-end development landscape in 2025, recruiters are tasked with identifying developers who can navigate its ecosystem with confidence and expertise. React's declarative nature, component-based architecture, and seamless integration with modern web development make it indispensable for building dynamic and scalable user interfaces.

This resource, "100+ React Interview Questions and Answers," is tailored for recruiters to simplify the evaluation process. It covers a range of topics, from React basics to advanced concepts such as hooks, state management, performance optimization, server-side rendering (SSR), and TypeScript integration.

Whether you're hiring entry-level developers or senior engineers, this guide enables you to assess a candidate’s:

  • Core React Knowledge: Components, props, state, and lifecycle methods.
  • Advanced Skills: Context API, custom hooks, and React Router.
  • Real-World Proficiency: Optimizing performance, debugging, and testing with tools like Jest and React Testing Library.

For a streamlined assessment process, consider platforms like WeCP, which allow you to:

  • Create customized React-based assessments.
  • Include hands-on coding tasks and real-world scenarios.
  • Proctor exams remotely while ensuring integrity.
  • Evaluate results with AI-driven analysis for faster decision-making.

Save time, enhance your interview process, and confidently hire React developers who can build exceptional user experiences and contribute effectively from day one.

React Interview Questions for Freshers/Beginners

  1. What is React?
  2. What are components in React?
  3. What is JSX?
  4. What is the purpose of the render() method in React?
  5. How do you create a functional component?
  6. What is the difference between functional and class components?
  7. What are props in React?
  8. How do you pass data from a parent component to a child component?
  9. What is state in React?
  10. How do you manage state in a functional component?
  11. What is the purpose of setState in React?
  12. What are lifecycle methods in React?
  13. What is the purpose of the key prop in React?
  14. How do you handle events in React?
  15. What is a default export in a React component?
  16. How do you import a component in React?
  17. What is the significance of the useEffect hook?
  18. How can you conditionally render a component in React?
  19. What is the difference between null and undefined in JavaScript?
  20. What are some advantages of using React?
  21. What is the use of the componentDidMount lifecycle method?
  22. How do you use map() to render a list of components?
  23. What is the difference between state and props?
  24. How do you handle forms in React?
  25. What are default props in React?
  26. How do you prevent default form submission in React?
  27. What is a class component in React?
  28. What is the purpose of the constructor in class components?
  29. How do you use inline styles in React?
  30. What are the advantages of using functional components?
  31. What is the this keyword in React, and how is it used?
  32. How do you handle multiple state values in a functional component?
  33. What is the purpose of the componentWillUnmount method?
  34. What is the use of the componentDidCatch method?
  35. How can you access props in a functional component?
  36. How do you use destructuring in React props?
  37. What is the purpose of React.StrictMode?
  38. How do you handle error boundaries in React?
  39. What is a ref in React, and how is it used?
  40. How do you implement conditional rendering in React?

React Interview Questions for Intermediates

  1. What are hooks in React? Can you name a few?
  2. What is the useState hook, and how is it used?
  3. What is the useEffect hook, and when would you use it?
  4. What are controlled components in React?
  5. How do you handle forms in React?
  6. What is prop drilling, and how can you avoid it?
  7. What is the difference between componentDidMount and componentDidUpdate?
  8. How can you conditionally apply CSS classes in React?
  9. Explain how to lift state up in React.
  10. What is React Context, and when would you use it?
  11. How can you create a higher-order component (HOC)?
  12. What is the difference between React.Component and React.PureComponent?
  13. What is the purpose of React.Fragment?
  14. How do you implement error boundaries in React?
  15. What is the useReducer hook, and when would you use it?
  16. How do you use the useMemo and useCallback hooks?
  17. What are the pros and cons of using class components vs. functional components?
  18. What is the role of keys in lists, and why are they important?
  19. How do you implement routing in a React application?
  20. What is the significance of using PropTypes in a React component?
  21. How do you manage side effects in React components?
  22. What is the purpose of React.StrictMode?
  23. How can you optimize performance in React applications?
  24. What is code splitting, and how can you achieve it in React?
  25. How can you fetch data in a functional component?
  26. How do you handle authentication in a React application?
  27. What is the significance of the useLayoutEffect hook?
  28. How do you set default props in a functional component?
  29. What is the purpose of the useRef hook?
  30. How can you share state between components using Context API?
  31. What are some common anti-patterns in React?
  32. How do you handle form validation in React?
  33. What is the role of middleware in React applications?
  34. How can you implement lazy loading for components in React?
  35. What is the difference between shallow rendering and full DOM rendering in testing?
  36. What are the best practices for structuring a React application?
  37. How do you create a custom hook in React?
  38. What is the purpose of the useImperativeHandle hook?
  39. How do you implement search functionality in a React application?
  40. How can you handle API errors in a React component?

React Interview Questions for Experienced Professionals

  1. What is the virtual DOM, and how does React use it?
  2. Explain React’s reconciliation process.
  3. How does the shouldComponentUpdate method work?
  4. What are some techniques for optimizing performance in React?
  5. What is the significance of React.memo?
  6. Can you explain render props and how to implement them?
  7. What is the difference between useEffect and useLayoutEffect?
  8. How do you manage side effects in React applications?
  9. What are some common performance pitfalls in React?
  10. How can you test React components effectively?
  11. Explain the differences between useReducer and useState.
  12. How do you implement server-side rendering in React?
  13. What is code splitting in React, and how can you implement it?
  14. How do you handle authentication in a React application?
  15. What are some best practices for structuring a React application?
  16. How can you create a custom hook in React?
  17. What is the role of the useImperativeHandle hook?
  18. How do you handle global state in a React application?
  19. What is the purpose of the useContext hook?
  20. How do you ensure the security of your React application?
  21. What are the implications of using TypeScript with React?
  22. How can you implement Progressive Web App (PWA) features in React?
  23. What is the role of a state management library like Redux?
  24. How do you handle versioning in APIs consumed by a React application?
  25. What are some common patterns for managing complex state in React?
  26. How do you optimize images and assets in a React application?
  27. What is the significance of React DevTools in debugging?
  28. How do you implement WebSocket communication in a React application?
  29. What are the benefits and challenges of using server-side rendering?
  30. How do you handle cross-origin requests in React?
  31. What are some strategies for enhancing accessibility in a React application?
  32. How do you perform integration testing for React applications?
  33. What is the role of useEffect in data fetching?
  34. How do you implement caching in a React application?
  35. What are the benefits of using component libraries in React?
  36. How do you manage performance in large-scale React applications?
  37. How do you implement responsive design in a React application?
  38. How do you ensure your React application is SEO-friendly?
  39. How do you manage dependencies in a React project?
  40. What are some future trends you see in the React ecosystem?

React Interview Questions and Answers in 2025

React Interview Questions and Answers for Freshers/Beginners

1. What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces, primarily for single-page applications (SPAs). Developed by Facebook, it allows developers to create large web applications that can change data without reloading the page. Its key features include:

  • Component-Based Architecture: React encourages the creation of reusable UI components that manage their own state. This modular approach makes it easier to maintain and reuse code.
  • Virtual DOM: React uses a virtual representation of the DOM to optimize rendering. Instead of updating the entire DOM tree for every change, React only updates the parts of the DOM that have changed, leading to better performance.
  • Unidirectional Data Flow: Data in React flows in one direction, from parent to child components, which makes it easier to understand how data changes in an application.
  • Ecosystem: React has a rich ecosystem that includes libraries for routing (React Router), state management (Redux), and more, which helps developers build robust applications.

2. What are components in React?

Components are the building blocks of a React application. They are JavaScript functions or classes that return React elements (JSX). There are two main types of components in React:

Functional Components: These are simpler and are defined as JavaScript functions.

They can accept props as arguments and return JSX.

const MyComponent = (props) => {
    return <div>{props.message}</div>;
};

Class Components: These are defined using ES6 class syntax and can maintain their own state and lifecycle methods.

class MyComponent extends React.Component {
    render() {
        return <div>{this.props.message}</div>;
    }
}

Components can be nested, managed, and composed to build complex UIs. They promote code reusability and separation of concerns.

3. What is JSX?

JSX (JavaScript XML) is a syntax extension for JavaScript that allows developers to write HTML-like code within their JavaScript files. JSX makes it easier to create React elements by providing a more intuitive and readable way to describe the UI. When using JSX, developers can combine HTML with JavaScript logic:

const element = <h1>Hello, world!</h1>;

JSX is not required to use React, but it is widely adopted because it improves the developer experience. Behind the scenes, JSX is transpiled to JavaScript function calls (e.g., React.createElement), which the React library can render into the DOM.

4. What is the purpose of the render() method in React?

The render() method is a key method in class components responsible for describing what the UI should look like. It returns JSX that represents the component's structure. This method is called whenever the component’s state or props change, triggering a re-render. Here's an example:

class MyComponent extends React.Component {
    render() {
        return <div>{this.props.message}</div>;
    }
}

In functional components, you do not use a render() method. Instead, the function itself returns JSX. The render() method is vital for rendering dynamic content based on the component's state and props.

5. How do you create a functional component?

A functional component in React is created using a JavaScript function that accepts props as an argument and returns JSX. Functional components can be defined as arrow functions or regular functions. Here’s an example of both:

// Arrow Function
const MyComponent = (props) => {
    return <div>{props.message}</div>;
};

// Regular Function
function MyComponent(props) {
    return <div>{props.message}</div>;
}

Functional components are easier to read and test than class components. With the introduction of hooks, functional components can also manage state and side effects.

6. What is the difference between functional and class components?

The primary differences between functional and class components in React are:

  • State Management:
    • Class Components: Can hold and manage their own state using this.state and this.setState().
    • Functional Components: Use the useState hook to manage state.
  • Lifecycle Methods:
    • Class Components: Can use lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.
    • Functional Components: Use the useEffect hook to handle side effects and lifecycle events.
  • Syntax:
    • Class Components: Require a class declaration and render() method.
    • Functional Components: Are simpler and consist of just a function that returns JSX.

Example:

// Class Component
class MyClassComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }
    render() {
        return <div>{this.state.count}</div>;
    }
}

// Functional Component
const MyFunctionalComponent = () => {
    const [count, setCount] = useState(0);
    return <div>{count}</div>;
};

With React's hooks, functional components have become more powerful and are preferred for new development.

7. What are props in React?

Props (short for properties) are read-only data passed from a parent component to a child component in React. They allow components to communicate and share data. Props can be any type of data, including strings, numbers, objects, functions, or JSX elements. Here's how you can use props:

const ChildComponent = (props) => {
    return <div>{props.name}</div>;
};

// Parent Component
const ParentComponent = () => {
    return <ChildComponent name="John Doe" />;
};

Props are immutable within the child component, meaning the child cannot modify them. This unidirectional data flow helps maintain predictable and manageable code.

8. How do you pass data from a parent component to a child component?

To pass data from a parent component to a child component, you use props. The parent component includes the child component in its JSX and provides the desired data as attributes. For example:

const ParentComponent = () => {
    const message = "Hello from Parent";
    return <ChildComponent text={message} />;
};

const ChildComponent = (props) => {
    return <div>{props.text}</div>;
};

In this example, the ParentComponent passes the message variable to the ChildComponent via the text prop. The child component can then access this data through its props.

9. What is state in React?

State is an object that represents the parts of a component that can change over time. Each component can maintain its own state, which allows it to keep track of dynamic data that affects rendering. When state changes, React re-renders the component to reflect the new state.

For class components, state is initialized in the constructor and updated using this.setState(). For functional components, state can be managed using the useState hook. Example:

// Class Component
class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }
    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };
    render() {
        return <div>{this.state.count}</div>;
    }
}

// Functional Component
const MyFunctionalComponent = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    return <div>{count}</div>;
};

Using state allows components to respond to user input, handle dynamic data, and manage the user interface effectively.

10. How do you manage state in a functional component?

In functional components, state is managed using the useState hook, which allows you to declare state variables. The useState hook takes an initial state value and returns an array containing the current state value and a function to update it. Here's an example:

import React, { useState } from 'react';

const Counter = () => {
    const [count, setCount] = useState(0); // Declare a state variable

    const increment = () => {
        setCount(count + 1); // Update state
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={increment}>Increment</button>
        </div>
    );
};

In this example, count is a state variable initialized to 0. The setCount function updates the count value when the button is clicked. When state changes, the component re-renders to reflect the new state.

11. What is the purpose of setState in React?

setState is a method used in class components to update the component's state. It is asynchronous and triggers a re-render of the component, allowing the UI to reflect the new state. The setState method takes an object that represents the new state or a function that receives the current state and props. Here’s an example:

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }

    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return <button onClick={this.increment}>{this.state.count}</button>;
    }
}

In this example, clicking the button increments the count state by 1, and the component re-renders to display the updated count. Using setState is crucial for maintaining the dynamic behavior of React components.

12. What are lifecycle methods in React?

Lifecycle methods are special methods in class components that allow you to hook into different stages of a component's lifecycle. These methods enable developers to execute code at specific points, such as when the component is created, updated, or unmounted. Key lifecycle methods include:

  • componentDidMount: Invoked immediately after a component is mounted. Ideal for fetching data or setting up subscriptions.
  • componentDidUpdate: Called after an update occurs. Useful for responding to prop or state changes.
  • componentWillUnmount: Invoked just before a component is unmounted and destroyed. Good for cleanup tasks, like canceling network requests or removing event listeners.

Example:

class MyComponent extends React.Component {
    componentDidMount() {
        console.log("Component mounted");
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("Component updated");
    }

    componentWillUnmount() {
        console.log("Component will unmount");
    }

    render() {
        return <div>Hello World</div>;
    }
}

In functional components, you can replicate lifecycle behavior using the useEffect hook.

13. What is the purpose of the key prop in React?

The key prop is a special attribute used in lists of React components to provide a unique identifier for each element. It helps React optimize rendering by keeping track of which items have changed, been added, or been removed. When rendering lists, using keys ensures that components maintain their identities across updates. Keys should be stable, unique, and predictable:

const items = ['Apple', 'Banana', 'Cherry'];
const listItems = items.map((item, index) => <li key={index}>{item}</li>);

In this example, each list item has a unique key based on its index in the array. However, using index as a key can lead to issues if the list can change. It's generally better to use unique identifiers from the data (e.g., an ID).

14. How do you handle events in React?

Event handling in React is similar to handling events in the DOM but with some differences. React uses camelCase for event names and passes the event object as the first argument to the event handler. You attach event handlers using curly braces. Here’s an example:

class MyComponent extends React.Component {
    handleClick = () => {
        alert("Button clicked!");
    };

    render() {
        return <button onClick={this.handleClick}>Click Me</button>;
    }
}

In functional components, you can handle events similarly:

const MyComponent = () => {
    const handleClick = () => {
        alert("Button clicked!");
    };

    return <button onClick={handleClick}>Click Me</button>;
};

It's important to bind the event handler to the component's context (using arrow functions or .bind(this)) in class components, so this refers to the component instance.

15. What is a default export in a React component?

A default export in a React component allows you to export a single value or component from a module. This component can be imported without using curly braces in other modules. Here’s an example:

// MyComponent.js
const MyComponent = () => {
    return <div>Hello World</div>;
};

export default MyComponent;

// AnotherFile.js
import MyComponent from './MyComponent';

In this case, MyComponent is the default export from MyComponent.js, and it can be imported directly in another file without braces.

16. How do you import a component in React?

To import a component in React, you use the import statement, specifying the component's file path. If the component is a default export, you can import it without curly braces. For named exports, you need to use curly braces. Examples:

// Importing a default export
import MyComponent from './MyComponent';

// Importing named exports
import { MyComponent, AnotherComponent } from './MyComponents';

Make sure to use the correct path relative to the importing file. You can also rename imports using the as keyword:

import { MyComponent as CustomComponent } from './MyComponents';

17. What is the significance of the useEffect hook?

The useEffect hook is used in functional components to perform side effects, such as fetching data, subscribing to events, or manipulating the DOM. It serves a similar purpose to lifecycle methods in class components (componentDidMount, componentDidUpdate, and componentWillUnmount). The useEffect hook takes two arguments: a function that contains the side effect and an optional dependency array that determines when the effect should run. Example:

import React, { useEffect, useState } from 'react';

const MyComponent = () => {
    const [data, setData] = useState([]);

    useEffect(() => {
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => setData(data));

        // Cleanup function (optional)
        return () => {
            console.log("Cleanup");
        };
    }, []); // Runs once when the component mounts

    return <div>{JSON.stringify(data)}</div>;
};

In this example, the effect runs once after the component mounts because the dependency array is empty. If you include dependencies, the effect will re-run whenever any of those dependencies change.

18. How can you conditionally render a component in React?

Conditional rendering in React allows you to render components based on certain conditions. You can use JavaScript expressions, if statements, or the ternary operator for conditional rendering. Here are some common techniques:

Using the if statement:

const MyComponent = ({ isLoggedIn }) => {
    if (isLoggedIn) {
        return <Dashboard />;
    } else {
        return <Login />;
    }
};

1. Using the ternary operator:

const MyComponent = ({ isLoggedIn }) => {
    return isLoggedIn ? <Dashboard /> : <Login />;
};

2. Using logical AND (&&):

const MyComponent = ({ isLoggedIn }) => {
    return (
        <div>
            {isLoggedIn && <Dashboard />}
            {!isLoggedIn && <Login />}
        </div>
    );
};

3. In each of these examples, the rendered component changes based on the value of isLoggedIn.

19. What is the difference between null and undefined in JavaScript?

In JavaScript, null and undefined are both primitive values, but they have distinct meanings:

null: Represents an intentional absence of any object value. It is often used to indicate that a variable has been declared but has not been assigned a value.

let myVar = null; // Explicitly set to "no value"

undefined: Indicates that a variable has been declared but has not yet been assigned a value or that a property does not exist in an object. If a function does not return a value, it returns undefined by default.

let myVar; // Implicitly undefined

The key difference is that null is a value that you assign to a variable, while undefined is the default state of uninitialized variables.

20. What are some advantages of using React?

React offers several advantages for building user interfaces:

  • Component-Based Architecture: Encourages reusable and modular components, making it easier to manage and maintain code.
  • Virtual DOM: Enhances performance by minimizing direct DOM manipulations, allowing React to efficiently update the UI by re-rendering only the changed components.
  • Unidirectional Data Flow: Simplifies data management, making it easier to understand how data flows through the application and debug issues.
  • Rich Ecosystem: Offers a variety of libraries and tools (like React Router and Redux) that complement its core functionality and help in building complex applications.
  • Strong Community Support: Has a large and active community, providing extensive resources, tutorials, and third-party libraries, facilitating learning and development.
  • Declarative Syntax: Allows developers to describe how the UI should look based on the current state, leading to clearer and more predictable code.

21. What is the use of the componentDidMount lifecycle method?

The componentDidMount method is a lifecycle method in class components that is called immediately after a component is mounted in the DOM. This is an ideal place for executing any side effects, such as data fetching, subscribing to events, or performing any setup that requires DOM nodes. It is only called once during the component's lifecycle.

Example:

class MyComponent extends React.Component {
    componentDidMount() {
        // Fetch data from an API
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => console.log(data));
    }

    render() {
        return <div>Data loaded!</div>;
    }
}

In this example, the API call to fetch data is made after the component mounts, ensuring that the component is ready to interact with the DOM.

22. How do you use map() to render a list of components?

In React, you can use the map() function to iterate over an array of data and render a list of components dynamically. Each component in the list should have a unique key prop to help React identify which items have changed, been added, or been removed.

Example:

const ItemList = ({ items }) => {
    return (
        <ul>
            {items.map((item, index) => (
                <li key={index}>{item}</li>
            ))}
        </ul>
    );
};

// Usage
const items = ['Apple', 'Banana', 'Cherry'];
<ItemList items={items} />;

In this example, the ItemList component receives an array of items, and map() is used to create a list of <li> elements.

23. What is the difference between state and props?

State and props are two core concepts in React that are used to manage data in components:

  • State:
    • Managed within the component.
    • Can be changed and updated using setState in class components or the useState hook in functional components.
    • Used to represent the internal data of a component that can change over time.

Example:

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }

    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return <button onClick={this.increment}>{this.state.count}</button>;
    }
}

  • Props:
    • Short for "properties".
    • Passed to the component from its parent.
    • Immutable within the child component; they cannot be changed by the child component.

Example:

const Greeting = ({ name }) => {
    return <h1>Hello, {name}!</h1>;
};

<Greeting name="Alice" />;

In this example, name is a prop passed to the Greeting component.

24. How do you handle forms in React?

Handling forms in React involves managing the form data using state and handling events like submission and input changes. You typically use controlled components, where form data is stored in the component's state.

Example:

class MyForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = { name: '' };
    }

    handleChange = (event) => {
        this.setState({ name: event.target.value });
    };

    handleSubmit = (event) => {
        event.preventDefault();
        console.log('Submitted name:', this.state.name);
    };

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input
                    type="text"
                    value={this.state.name}
                    onChange={this.handleChange}
                />
                <button type="submit">Submit</button>
            </form>
        );
    }
}

In this example, the MyForm component maintains the input value in its state and updates it with handleChange. On form submission, handleSubmit prevents the default behavior and logs the submitted name.

25. What are default props in React?

Default props are used to set default values for props in a component. If a parent component does not provide a specific prop, the component will fall back to the default value defined in defaultProps. This is particularly useful for ensuring that a component has a predictable behavior even when certain props are not passed.

Example:

class MyComponent extends React.Component {
    render() {
        return <div>{this.props.message}</div>;
    }
}

MyComponent.defaultProps = {
    message: 'Default message',
};

// Usage
<MyComponent />; // Renders "Default message"
<MyComponent message="Custom message" />; // Renders "Custom message"

In this example, if message is not provided, it defaults to "Default message".

26. How do you prevent default form submission in React?

To prevent the default form submission behavior in React, you can call event.preventDefault() within the form's onSubmit event handler. This stops the page from refreshing and allows you to handle the form submission with your own logic.

Example:

const MyForm = () => {
    const handleSubmit = (event) => {
        event.preventDefault(); // Prevents the default form submission
        console.log('Form submitted');
    };

    return (
        <form onSubmit={handleSubmit}>
            <input type="text" />
            <button type="submit">Submit</button>
        </form>
    );
};

In this example, calling preventDefault() in the handleSubmit function prevents the page from refreshing when the form is submitted.

27. What is a class component in React?

A class component is a JavaScript class that extends React.Component and includes a render method, which returns React elements to be displayed on the UI. Class components can maintain internal state and lifecycle methods, making them suitable for managing more complex components.

Example:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }

    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return (
            <div>
                <p>Count: {this.state.count}</p>
                <button onClick={this.increment}>Increment</button>
            </div>
        );
    }
}

In this example, MyComponent is a class component that manages a count state and updates it when the button is clicked.

28. What is the purpose of the constructor in class components?

The constructor in class components is a special method that is called when a component is created. It is primarily used for two purposes:

  1. Initializing state: The constructor allows you to set the initial state of the component using this.state.
  2. Binding methods: It is also common to bind class methods to the component instance to ensure that this refers to the component instance when the method is called.

Example:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
        this.increment = this.increment.bind(this); // Binding the method
    }

    increment() {
        this.setState({ count: this.state.count + 1 });
    }

    render() {
        return <button onClick={this.increment}>{this.state.count}</button>;
    }
}

In this example, the constructor initializes the state and binds the increment method.

29. How do you use inline styles in React?

In React, you can apply inline styles to elements using the style attribute. The style attribute accepts a JavaScript object where the keys are camelCased versions of the CSS property names, and the values are the corresponding CSS values.

Example:

const MyComponent = () => {
    const style = {
        color: 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
    };

    return <div style={style}>This is a styled component!</div>;
};

In this example, the style object is defined with CSS properties, and it is applied to the <div> using the style attribute.

30. What are the advantages of using functional components?

Functional components are simpler and more concise than class components. Here are some advantages of using functional components:

  • Simpler Syntax: Functional components are written as plain JavaScript functions, making them easier to read and understand.
  • Hooks: With the introduction of hooks in React 16.8, functional components can now use state and other features that were previously only available in class components.
  • No this Binding: Functional components do not have this, which simplifies the code since there’s no need to bind methods.
  • Performance: In some cases, functional components can lead to better performance because they are typically easier to optimize, especially with memoization (using React.memo).
  • Better for Presentational Components: They are often used for presentational components that only render UI based on props, keeping the component logic focused and clean.

Example:

const Greeting = ({ name }) => {
    return <h1>Hello, {name}!</h1>;
};

In this example, Greeting is a functional component hat receives a prop and renders it without any internal state or lifecycle methods.

31. What is the this keyword in React, and how is it used?

The this keyword in React refers to the current instance of the class component. It is used to access properties and methods of the component. In class components, this must be bound to methods in the constructor to ensure that it correctly refers to the component instance when the method is called (especially in event handlers).

Example:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
        this.increment = this.increment.bind(this); // Binding the method
    }

    increment() {
        this.setState({ count: this.state.count + 1 });
    }

    render() {
        return <button onClick={this.increment}>{this.state.count}</button>;
    }
}

In this example, this is used to access setState and state. The method increment is bound to the class instance to ensure that this refers to the component.

32. How do you handle multiple state values in a functional component?

In functional components, you can manage multiple state values by using the useState hook for each state variable individually or by using a single useState call with an object to group the state values.

Example using multiple useState:

import React, { useState } from 'react';

const MyComponent = () => {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');

    return (
        <div>
            <button onClick={() => setCount(count + 1)}>Increment: {count}</button>
            <input
                type="text"
                value={name}
                onChange={(e) => setName(e.target.value)}
            />
            <p>Name: {name}</p>
        </div>
    );
};

Example using a single useState:

import React, { useState } from 'react';

const MyComponent = () => {
    const [formData, setFormData] = useState({ count: 0, name: '' });

    const increment = () => {
        setFormData((prevState) => ({
            ...prevState,
            count: prevState.count + 1,
        }));
    };

    const handleNameChange = (e) => {
        setFormData((prevState) => ({
            ...prevState,
            name: e.target.value,
        }));
    };

    return (
        <div>
            <button onClick={increment}>Increment: {formData.count}</button>
            <input
                type="text"
                value={formData.name}
                onChange={handleNameChange}
            />
            <p>Name: {formData.name}</p>
        </div>
    );
};

In both examples, we manage multiple state values in a functional component.

33. What is the purpose of the componentWillUnmount method?

The componentWillUnmount method is a lifecycle method in class components that is called just before a component is removed from the DOM. This method is useful for performing cleanup tasks, such as invalidating timers, canceling network requests, or removing event listeners.

Example:

class Timer extends React.Component {
    componentDidMount() {
        this.timerID = setInterval(() => this.tick(), 1000);
    }

    componentWillUnmount() {
        clearInterval(this.timerID); // Cleanup the timer
    }

    tick() {
        console.log('Tick');
    }

    render() {
        return <div>Timer is running!</div>;
    }
}

In this example, the timer is set up in componentDidMount, and it is cleared in componentWillUnmount to prevent memory leaks.

34. What is the use of the componentDidCatch method?

The componentDidCatch method is a lifecycle method used for error handling in class components. It is invoked when an error occurs in a child component. This method allows you to catch errors and perform actions such as logging the error or displaying a fallback UI.

Example:

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    static getDerivedStateFromError(error) {
        // Update state to render fallback UI
        return { hasError: true };
    }

    componentDidCatch(error, info) {
        // Log the error to an error reporting service
        console.error("Error occurred:", error, info);
    }

    render() {
        if (this.state.hasError) {
            return <h1>Something went wrong.</h1>;
        }

        return this.props.children; 
    }
}

// Usage
<ErrorBoundary>
    <MyComponent />
</ErrorBoundary>

In this example, ErrorBoundary catches errors from its child components and renders a fallback UI when an error occurs.

35. How can you access props in a functional component?

In a functional component, props are accessed as a parameter of the function. You can destructure the props object directly in the function signature or access the props using the props parameter.

Example using destructuring:

const Greeting = ({ name }) => {
    return <h1>Hello, {name}!</h1>;
};

// Usage
<Greeting name="Alice" />;

Example accessing props directly:

const Greeting = (props) => {
    return <h1>Hello, {props.name}!</h1>;
};

// Usage
<Greeting name="Bob" />;

In both examples, the Greeting component accesses the name prop to render the greeting message.

36. How do you use destructuring in React props?

Destructuring allows you to extract values from objects or arrays into distinct variables. In React, you can destructure props to access specific properties directly without needing to refer to the props object repeatedly.

Example:

const UserProfile = ({ name, age, location }) => {
    return (
        <div>
            <h2>Name: {name}</h2>
            <p>Age: {age}</p>
            <p>Location: {location}</p>
        </div>
    );
};

// Usage
<UserProfile name="John Doe" age={30} location="New York" />;

In this example, the UserProfile component destructures the name, age, and location props from the props object, allowing for cleaner and more readable code.

37. What is the purpose of React.StrictMode?

React.StrictMode is a tool for highlighting potential problems in an application. It is a wrapper component that activates additional checks and warnings for its descendants. It does not affect the production build, only the development environment, and is helpful for identifying unsafe lifecycle methods, deprecated APIs, and other potential issues.

Example:

import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
    return <h1>Hello, World!</h1>;
};

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById('root')
);

In this example, React.StrictMode wraps the App component, enabling checks for the component during development.

38. How do you handle error boundaries in React?

Error boundaries are components that catch JavaScript errors in their child component tree, log those errors, and display a fallback UI instead of crashing the entire component tree. You can create an error boundary by defining a class component with componentDidCatch and getDerivedStateFromError lifecycle methods.

Example:

class MyErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    static getDerivedStateFromError(error) {
        return { hasError: true };
    }

    componentDidCatch(error, info) {
        console.error("Error caught:", error, info);
    }

    render() {
        if (this.state.hasError) {
            return <h1>Something went wrong.</h1>;
        }

        return this.props.children;
    }
}

// Usage
<MyErrorBoundary>
    <MyComponent />
</MyErrorBoundary>

In this example, MyErrorBoundary will catch errors from its children and render an error message if an error occurs.

39. What is a ref in React, and how is it used?

A ref in React is a way to access a DOM element or a class component instance directly. It is created using the React.createRef() method and is often used for managing focus, text selection, or triggering animations.

Example:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.inputRef = React.createRef();
    }

    focusInput = () => {
        this.inputRef.current.focus(); // Focus on the input element
    };

    render() {
        return (
            <div>
                <input ref={this.inputRef} type="text" />
                <button onClick={this.focusInput}>Focus Input</button>
            </div>
        );
    }
}

In this example, clicking the button focuses the input field by directly accessing it through the inputRef.

40. How do you implement conditional rendering in React?

Conditional rendering in React can be implemented using JavaScript expressions to determine which components or elements should be rendered based on certain conditions. Common approaches include using the ternary operator, logical AND (&&), or if-else statements.

Example using the ternary operator:

const Greeting = ({ isLoggedIn }) => {
    return (
        <div>
            {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please log in.</h1>}
        </div>
    );
};

// Usage
<Greeting isLoggedIn={true} />;

Example using logical AND:

const Notifications = ({ notifications }) => {
    return (
        <div>
            {notifications.length > 0 && <h2>You have notifications!</h2>}
        </div>
    );
};

// Usage
<Notifications notifications={['Message 1', 'Message 2']} />;

In these examples, the output changes based on the value of isLoggedIn or the length of the notifications array, demonstrating how to implement conditional rendering effectively.

Intermediate level

1. What are hooks in React? Can you name a few?

Hooks are functions that let you use state and other React features without writing a class. They were introduced in React 16.8 to allow functional components to manage state and side effects, making it easier to reuse stateful logic.

Common hooks include:

  • useState: Allows functional components to add state.
  • useEffect: Manages side effects in functional components.
  • useContext: Consumes context in functional components.
  • useReducer: Manages complex state logic in functional components.
  • useMemo: Memoizes values to optimize performance.
  • useCallback: Memoizes callback functions to prevent unnecessary re-renders.

2. What is the useState hook, and how is it used?

The useState hook is used to add state to functional components. It returns an array with two elements: the current state value and a function to update that state.

Example:

import React, { useState } from 'react';

const Counter = () => {
    const [count, setCount] = useState(0); // Initialize state with 0

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
};

In this example, count holds the current count value, and setCount is used to update the count when the button is clicked.

3. What is the useEffect hook, and when would you use it?

The useEffect hook allows you to perform side effects in functional components. Side effects can include data fetching, subscriptions, or manually changing the DOM. It can run after every render or conditionally based on dependencies.

Example:

import React, { useState, useEffect } from 'react';

const DataFetcher = () => {
    const [data, setData] = useState([]);

    useEffect(() => {
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => setData(data));
    }, []); // Empty dependency array means it runs once after the first render

    return (
        <ul>
            {data.map(item => (
                <li key={item.id}>{item.name}</li>
            ))}
        </ul>
    );
};

In this example, useEffect is used to fetch data when the component mounts. The empty dependency array ensures the effect runs only once.

4. What are controlled components in React?

Controlled components are components whose form data is controlled by the React component's state. The input elements do not maintain their own state; instead, their value is set by the state of the component, making React the single source of truth.

Example:

import React, { useState } from 'react';

const ControlledForm = () => {
    const [inputValue, setInputValue] = useState('');

    const handleChange = (event) => {
        setInputValue(event.target.value); // Update state on input change
    };

    return (
        <form>
            <input type="text" value={inputValue} onChange={handleChange} />
            <p>You typed: {inputValue}</p>
        </form>
    );
};

In this example, the input's value is controlled by inputValue in the component state.

5. How do you handle forms in React?

Handling forms in React typically involves using controlled components. You manage the state of the form inputs, handle changes, and perform actions on submission.

Basic steps to handle forms:

  1. Create state variables for each input field.
  2. Use controlled components to link the input value to state.
  3. Define a function to handle form submission.
  4. Optionally, perform validation.

Example:

import React, { useState } from 'react';

const MyForm = () => {
    const [name, setName] = useState('');

    const handleSubmit = (event) => {
        event.preventDefault(); // Prevent default form submission behavior
        console.log('Submitted name:', name);
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={name}
                onChange={(e) => setName(e.target.value)}
            />
            <button type="submit">Submit</button>
        </form>
    );
};

In this example, the form captures the user's name and logs it upon submission.

6. What is prop drilling, and how can you avoid it?

Prop drilling occurs when you pass data through many layers of components just to get it to a deeply nested component. This can make the code harder to maintain and understand.

To avoid prop drilling, you can use:

  • React Context: Provides a way to share values between components without explicitly passing props through every level.
  • Redux: A state management library that can manage global state and provide it to any component.

Example using React Context:

const ThemeContext = React.createContext();

const App = () => {
    const theme = 'dark';

    return (
        <ThemeContext.Provider value={theme}>
            <Toolbar />
        </ThemeContext.Provider>
    );
};

const Toolbar = () => {
    return (
        <div>
            <ThemedButton />
        </div>
    );
};

const ThemedButton = () => {
    const theme = React.useContext(ThemeContext);
    return <button className={theme}>I am styled by {theme} theme!</button>;
};

In this example, ThemeContext is used to avoid passing the theme prop through each level of components.

7. What is the difference between componentDidMount and componentDidUpdate?

  • componentDidMount: This lifecycle method is called once, immediately after a component is mounted to the DOM. It is commonly used for data fetching, setting up subscriptions, or initiating side effects.
  • componentDidUpdate: This lifecycle method is called immediately after updating occurs. It is useful for responding to prop or state changes (e.g., making an API call when a specific prop changes).

Example:

class ExampleComponent extends React.Component {
    componentDidMount() {
        console.log('Component mounted');
    }

    componentDidUpdate(prevProps) {
        if (this.props.data !== prevProps.data) {
            console.log('Data changed:', this.props.data);
        }
    }
}

In this example, componentDidMount logs a message when the component mounts, while componentDidUpdate logs changes when the data prop updates.

8. How can you conditionally apply CSS classes in React?

You can conditionally apply CSS classes in React by using JavaScript expressions or libraries like classnames. This allows you to dynamically set classes based on component state or props.

Example using a ternary operator:

const Button = ({ isActive }) => {
    return (
        <button className={isActive ? 'active' : 'inactive'}>
            Click Me
        </button>
    );
};

Example using classnames library:

import classNames from 'classnames';

const Button = ({ isActive, isDisabled }) => {
    const buttonClass = classNames({
        active: isActive,
        inactive: !isActive,
        disabled: isDisabled,
    });

    return <button className={buttonClass}>Click Me</button>;
};

In both examples, the button's class is determined based on the isActive and isDisabled props.

9. Explain how to lift state up in React.

Lifting state up is the process of moving the state from a child component to a common parent component. This allows the parent component to manage the state and pass it down as props to child components.

Steps to lift state up:

  1. Identify the common parent component that needs access to the state.
  2. Move the state and state-updating logic to the parent component.
  3. Pass the state and a function to update the state down to the child components as props.

Example:

const Parent = () => {
    const [count, setCount] = useState(0);

    return (
        <div>
            <ChildA count={count} />
            <ChildB onIncrement={() => setCount(count + 1)} />
        </div>
    );
};

const ChildA = ({ count }) => <h1>{count}</h1>;

const ChildB = ({ onIncrement }) => (
    <button onClick={onIncrement}>Increment</button>
);

In this example, the count state is lifted to the Parent component, which can now pass it to ChildA and the function to update it to ChildB.

10. What is React Context, and when would you use it?

React Context is a feature that allows you to share values (such as state or functions) between components without having to pass props explicitly through every level of the component tree. It is useful for managing global state, themes, user authentication, or any data that needs to be accessed by multiple components at different levels.

When to use React Context:

  • When you have data that needs to be accessible by many components at different nesting levels.
  • When prop drilling becomes cumbersome or reduces the clarity of your component structure.

Example:

const UserContext = React.createContext();

const App = () => {
    const user = { name: 'John Doe' };

    return (
        <UserContext.Provider value={user}>
            <UserProfile />
        </UserContext.Provider>
    );
};

const UserProfile = () => {
    const user = React.useContext(UserContext);
    return <h1>{user.name}</h1>;
};

In this example, UserContext provides user information to UserProfile without needing to pass the user prop explicitly.

11. How can you create a higher-order component (HOC)?

A Higher-Order Component (HOC) is a function that takes a component and returns a new component. It is a pattern used to share common functionality between components without modifying their original structure.

Example:

import React from 'react';

// HOC that adds logging functionality
const withLogging = (WrappedComponent) => {
    return class extends React.Component {
        componentDidMount() {
            console.log('Component mounted:', WrappedComponent.name);
        }

        render() {
            return <WrappedComponent {...this.props} />;
        }
    };
};

// Example component
const MyComponent = (props) => {
    return <div>Hello, {props.name}!</div>;
};

// Wrapping the component with HOC
const MyComponentWithLogging = withLogging(MyComponent);

// Usage
<MyComponentWithLogging name="John" />;

In this example, withLogging is an HOC that logs a message when the wrapped component mounts. You can use HOCs to add features like logging, authentication, or data fetching to your components.

12. What is the difference between React.Component and React.PureComponent?

  • React.Component: This is the base class for creating components in React. Components that extend React.Component will re-render when their state or props change.
  • React.PureComponent: This class is similar to React.Component, but it implements a shallow comparison of props and state in the shouldComponentUpdate lifecycle method. This means that a PureComponent will only re-render if its props or state change shallowly.

Example:

class RegularComponent extends React.Component {
    render() {
        console.log('RegularComponent rendered');
        return <div>{this.props.value}</div>;
    }
}

class PureComponentExample extends React.PureComponent {
    render() {
        console.log('PureComponent rendered');
        return <div>{this.props.value}</div>;
    }
}

// Usage
<RegularComponent value="Hello" />;
<PureComponentExample value="Hello" />;

In this example, if you change the value prop to an identical object reference, the RegularComponent will re-render, while the PureComponentExample will not, thus optimizing performance.

13. What is the purpose of React.Fragment?

React.Fragment is a component that allows you to group multiple elements without adding an extra node to the DOM. It helps in avoiding unnecessary wrapper elements, which can be important for styling or layout purposes.

Example:

const List = () => {
    return (
        <React.Fragment>
            <li>Item 1</li>
            <li>Item 2</li>
        </React.Fragment>
    );
};

// Using shorthand syntax
const ListShort = () => (
    <>
        <li>Item 1</li>
        <li>Item 2</li>
    </>
);

In both examples, React.Fragment is used to wrap multiple <li> elements without creating an additional parent element in the DOM.

14. How do you implement error boundaries in React?

Error boundaries are React components that catch JavaScript errors in their child component tree, log those errors, and display a fallback UI instead of crashing the whole application. To create an error boundary, you need to implement the componentDidCatch lifecycle method and the getDerivedStateFromError static method.

Example:

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    static getDerivedStateFromError(error) {
        return { hasError: true }; // Update state to render fallback UI
    }

    componentDidCatch(error, info) {
        console.error('Error caught by Error Boundary:', error, info);
    }

    render() {
        if (this.state.hasError) {
            return <h1>Something went wrong.</h1>;
        }

        return this.props.children; // Render child components if no error
    }
}

// Usage
<ErrorBoundary>
    <MyComponent />
</ErrorBoundary>;

In this example, if MyComponent throws an error, the ErrorBoundary will catch it and display "Something went wrong" instead of crashing.

15. What is the useReducer hook, and when would you use it?

The useReducer hook is used for managing complex state logic in functional components. It is an alternative to useState that is preferable when dealing with state transitions based on previous state values or when the state shape is complex.

When to use useReducer:

  • When the state logic is complex and involves multiple sub-values.
  • When the next state depends on the previous state.
  • When you want to manage state in a more predictable way, similar to Redux.

Example:

import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        default:
            throw new Error();
    }
}

const Counter = () => {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <div>
            Count: {state.count}
            <button onClick={() => dispatch({ type: 'increment' })}>+</button>
            <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
        </div>
    );
};

In this example, useReducer is used to manage the count state. The reducer function defines how the state changes in response to actions.

16. How do you use the useMemo and useCallback hooks?

  • useMemo: This hook returns a memoized value. It is useful for optimizing performance by caching expensive calculations and recomputing them only when their dependencies change.

Example:

import React, { useMemo } from 'react';

const ExpensiveCalculation = ({ num }) => {
    const computedValue = useMemo(() => {
        return num * 2; // Expensive calculation
    }, [num]); // Recompute only when `num` changes

    return <div>{computedValue}</div>;
};

  • useCallback: This hook returns a memoized callback function. It is useful for preventing unnecessary re-renders of child components that rely on callback functions as props.

Example:

import React, { useCallback, useState } from 'react';

const ParentComponent = () => {
    const [count, setCount] = useState(0);

    const increment = useCallback(() => {
        setCount(c => c + 1);
    }, []); // Memoize function, will not change on re-renders

    return <ChildComponent onIncrement={increment} />;
};

const ChildComponent = React.memo(({ onIncrement }) => {
    return <button onClick={onIncrement}>Increment</button>;
});

In this example, useCallback is used to memoize the increment function, ensuring that ChildComponent does not re-render unnecessarily.

17. What are the pros and cons of using class components vs. functional components?

Class Components:

  • Pros:
    • Lifecycle methods are available, making it easier to manage side effects.
    • Can be easier to understand for those coming from an OOP background.
  • Cons:
    • More boilerplate code is required (constructor, binding methods).
    • May lead to confusion with this binding.

Functional Components:

  • Pros:
    • Less boilerplate code; simpler and cleaner syntax.
    • React hooks allow managing state and side effects in a more functional way.
    • Encourages composition and reuse of logic.
  • Cons:
    • Lack of lifecycle methods (although hooks provide alternatives).
    • May require a deeper understanding of hooks and functional programming.

18. What is the role of keys in lists, and why are they important?

Keys are unique identifiers assigned to elements in a list to help React identify which items have changed, been added, or removed. They should be stable, unique, and predictable.

Importance of keys:

  • Helps optimize rendering performance by allowing React to skip unnecessary re-renders.
  • Helps maintain component state between updates.

Example:

const ItemList = ({ items }) => {
    return (
        <ul>
            {items.map(item => (
                <li key={item.id}>{item.name}</li>
            ))}
        </ul>
    );
};

In this example, each item in the list has a unique key prop, enabling React to track which items have changed efficiently.

19. How do you implement routing in a React application?

Routing in a React application is typically managed using a library like react-router-dom. This library allows you to define routes for different components based on the URL path.

Basic implementation:

Install react-router-dom:

npm install react-router-dom

  1. Set up routing in your application:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './Home';
import About from './About';
import NotFound from './NotFound';

const App = () => {
    return (
        <Router>
            <Switch>
                <Route path="/" exact component={Home} />
                <Route path="/about" component={About} />
                <Route component={NotFound} /> {/* Fallback route */}
            </Switch>
        </Router>
    );
};

In this example, BrowserRouter is used to wrap the application, and Route is used to define the path and the corresponding component to render.

20. What is the significance of using PropTypes in a React component?

PropTypes is a library used for type-checking props in React components. It allows developers to validate the types of props passed to a component and provides warnings in the console if the types are incorrect. This helps in catching bugs and ensuring that components receive the expected data types.

Example:

import PropTypes from 'prop-types';

const MyComponent = ({ name, age }) => {
    return (
        <div>
            Name: {name}, Age: {age}
        </div>
    );
};

MyComponent.propTypes = {
    name: PropTypes.string.isRequired,
    age: PropTypes.number.isRequired,
};

In this example, MyComponent requires name to be a string and age to be a number. If the props do not match the specified types, a warning will be logged in the console during development.

21. How do you manage side effects in React components?

You can manage side effects in React components using the useEffect hook. This hook allows you to perform side effects such as data fetching, subscriptions, or manual DOM manipulation in functional components. You can specify dependencies for the effect to control when it runs.

Example:

import React, { useEffect, useState } from 'react';

const DataFetchingComponent = () => {
    const [data, setData] = useState(null);
    
    useEffect(() => {
        const fetchData = async () => {
            const response = await fetch('https://api.example.com/data');
            const result = await response.json();
            setData(result);
        };

        fetchData();
    }, []); // Empty array means this effect runs only once after the initial render

    return (
        <div>
            {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'}
        </div>
    );
};

In this example, useEffect is used to fetch data when the component mounts, and the fetched data is stored in the component's state.

22. What is the purpose of React.StrictMode?

React.StrictMode is a tool for highlighting potential problems in an application. It activates additional checks and warnings for its descendants, helping to identify issues related to deprecated APIs, unexpected side effects, and other common problems.

Key features:

  • Warns about legacy lifecycle methods.
  • Detects unexpected side effects during render.
  • Helps identify components that use deprecated APIs.

Example:

import React from 'react';
import MyComponent from './MyComponent';

const App = () => {
    return (
        <React.StrictMode>
            <MyComponent />
        </React.StrictMode>
    );
};

In this example, MyComponent is wrapped in React.StrictMode, enabling strict checks for it.

23. How can you optimize performance in React applications?

You can optimize performance in React applications using several techniques:

  1. Use React.PureComponent or React.memo: These help prevent unnecessary re-renders by performing shallow comparisons of props and state.
  2. Code Splitting: Use dynamic import() to split your code into smaller chunks that are loaded on demand.
  3. Use useMemo and useCallback: Memoize values and functions to avoid recomputing them on every render.
  4. Avoid Inline Functions: Use function references instead of inline functions in render methods to avoid creating new instances on each render.
  5. Optimize Images: Use optimized image formats and sizes to reduce load times.

24. What is code splitting, and how can you achieve it in React?

Code splitting is the practice of breaking your application into smaller bundles, which can be loaded on demand. This helps reduce the initial load time by only loading the code required for the initial render.

How to achieve code splitting:

  1. Dynamic Imports: Use the import() function to load components asynchronously.

Example:

import React, { Suspense } from 'react';

const LazyComponent = React.lazy(() => import('./LazyComponent'));

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

In this example, LazyComponent is loaded only when it is needed, and Suspense is used to show a fallback while the component is loading.

25. How can you fetch data in a functional component?

You can fetch data in a functional component using the useEffect hook along with the fetch API or any data-fetching library like Axios.

Example:

import React, { useEffect, useState } from 'react';

const DataFetchingComponent = () => {
    const [data, setData] = useState([]);

    useEffect(() => {
        const fetchData = async () => {
            const response = await fetch('https://api.example.com/data');
            const result = await response.json();
            setData(result);
        };

        fetchData();
    }, []); // Run only once after the initial render

    return (
        <div>
            {data.map(item => (
                <div key={item.id}>{item.name}</div>
            ))}
        </div>
    );
};

In this example, data is fetched and stored in the state when the component mounts.

26. How do you handle authentication in a React application?

Handling authentication in a React application typically involves the following steps:

  1. Create Authentication Context: Use the Context API to create a global authentication state.
  2. Implement Login/Logout Functions: Create functions to log in and log out users.
  3. Protect Routes: Use route guards to restrict access to certain components based on authentication status.

Example:

import React, { createContext, useState, useContext } from 'react';
import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom';

const AuthContext = createContext();

const AuthProvider = ({ children }) => {
    const [isAuthenticated, setIsAuthenticated] = useState(false);

    const login = () => setIsAuthenticated(true);
    const logout = () => setIsAuthenticated(false);

    return (
        <AuthContext.Provider value={{ isAuthenticated, login, logout }}>
            {children}
        </AuthContext.Provider>
    );
};

const PrivateRoute = ({ component: Component, ...rest }) => {
    const { isAuthenticated } = useContext(AuthContext);
    return (
        <Route
            {...rest}
            render={props =>
                isAuthenticated ? (
                    <Component {...props} />
                ) : (
                    <Redirect to="/login" />
                )
            }
        />
    );
};

// Usage in App component
const App = () => {
    return (
        <AuthProvider>
            <Router>
                <PrivateRoute path="/protected" component={ProtectedComponent} />
                <Route path="/login" component={LoginComponent} />
            </Router>
        </AuthProvider>
    );
};

In this example, the AuthProvider manages the authentication state, and the PrivateRoute component restricts access to the protected route.

27. What is the significance of the useLayoutEffect hook?

The useLayoutEffect hook is similar to useEffect, but it runs synchronously after all DOM mutations. This means that any updates made in useLayoutEffect will be reflected in the browser before the browser has a chance to paint.

When to use useLayoutEffect:

  • When you need to read layout from the DOM and synchronously re-render.
  • For measuring DOM elements and making synchronous adjustments before the browser paints.

Example:

import React, { useLayoutEffect, useRef } from 'react';

const LayoutEffectComponent = () => {
    const boxRef = useRef();

    useLayoutEffect(() => {
        const height = boxRef.current.clientHeight;
        console.log('Box height:', height);
    });

    return <div ref={boxRef} style={{ height: '100px' }}>Hello</div>;
};

In this example, useLayoutEffect is used to read the height of the DOM element immediately after it has been updated.

28. How do you set default props in a functional component?

You can set default props in a functional component using the defaultProps property. This is particularly useful for ensuring that your component has fallback values if certain props are not provided.

Example:

const MyComponent = ({ name }) => {
    return <div>Hello, {name}!</div>;
};

MyComponent.defaultProps = {
    name: 'Guest', // Default value
};

// Usage
<MyComponent />; // Will render "Hello, Guest!"

In this example, if name is not provided, the component will render "Hello, Guest!".

29. What is the purpose of the useRef hook?

The useRef hook is used to create a mutable object that persists for the full lifetime of the component. It is commonly used to access DOM elements directly, store a mutable value, or retain values across renders without causing re-renders.

Example:

import React, { useRef } from 'react';

const FocusInput = () => {
    const inputRef = useRef();

    const focusInput = () => {
        inputRef.current.focus(); // Focus the input element
    };

    return (
        <div>
            <input ref={inputRef} type="text" />
            <button onClick={focusInput}>Focus Input</button>
        </div>
    );
};

In this example, useRef is used to get a reference to the input element, allowing you to programmatically focus it.

30. How can you share state between components using Context API?

You can share state between components using the Context API by creating a context, providing it at a higher level in your component tree, and consuming it in child components.

Example:

import React, { createContext, useState, useContext } from 'react';

// Create context
const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light');

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    );
};

const ThemedComponent = () => {
    const { theme, setTheme } = useContext(ThemeContext);
    
    return (
        <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
            <p>The current theme is {theme}</p>
            <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Toggle Theme</button>
        </div>
    );
};

// Usage in App component
const App = () => {
    return (
        <ThemeProvider>
            <ThemedComponent />
        </ThemeProvider>
    );
};

In this example, the ThemeProvider provides the current theme and a function to toggle it, allowing any child component to access and modify the theme state.

31. What are some common anti-patterns in React?

Common anti-patterns in React include:

  1. Mutating State Directly: Always use setState or state updater functions to modify state, instead of mutating it directly.
  2. Using Index as Key in Lists: This can lead to issues with component state and performance. Use unique IDs instead.
  3. Overusing Context: Using Context for everything can lead to performance issues; use it sparingly for global state.
  4. Not Using key Prop in Lists: Always provide a unique key prop to list items to help React identify which items have changed.
  5. Handling Side Effects in Render Method: Use useEffect for side effects instead of putting them directly in the render method.

32. How do you handle form validation in React?

You can handle form validation in React using controlled components, state management, and validation libraries like Formik or Yup.

Example using local state:

import React, { useState } from 'react';

const FormValidation = () => {
    const [email, setEmail] = useState('');
    const [error, setError] = useState('');

    const validateEmail = (email) => {
        // Basic email validation
        const regex = /\S+@\S+\.\S+/;
        return regex.test(email);
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        if (!validateEmail(email)) {
            setError('Invalid email address');
        } else {
            setError('');
            // Submit the form
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input 
                type="email" 
                value={email} 
                onChange={(e) => setEmail(e.target.value)} 
                placeholder="Enter your email"
            />
            {error && <div style={{ color: 'red' }}>{error}</div>}
            <button type="submit">Submit</button>
        </form>
    );
};

In this example, the email input is validated on form submission, and an error message is displayed if the input is invalid.

33. What is the role of middleware in React applications?

Middleware in React applications, especially when using libraries like Redux, acts as a bridge between actions and the reducer. It allows you to intercept actions dispatched to the store and perform additional operations, such as logging, asynchronous API calls, or modifying the actions before they reach the reducer.

Common uses of middleware:

  1. Logging: Logging actions and state changes for debugging purposes.
  2. Async Operations: Handling asynchronous actions like API calls (e.g., using Redux Thunk or Redux Saga).
  3. Error Handling: Catching and handling errors globally.

Example using Redux Thunk:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

In this example, redux-thunk middleware is applied to the Redux store to handle asynchronous actions.

34. How can you implement lazy loading for components in React?

Lazy loading for components in React can be implemented using React.lazy and Suspense. This allows you to load components only when they are needed, reducing the initial load time.

Example:

import React, { Suspense } from 'react';

const LazyComponent = React.lazy(() => import('./LazyComponent'));

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

In this example, LazyComponent will only be loaded when it is rendered, and Suspense provides a fallback UI while loading.

35. What is the difference between shallow rendering and full DOM rendering in testing?

  • Shallow Rendering: In shallow rendering, only the component being tested is rendered, without rendering its child components. This is useful for unit testing and isolating the component's logic. It allows you to test the component's output and behavior without worrying about the implementation details of child components.
  • Full DOM Rendering: Full DOM rendering renders the entire component tree, including child components. This approach is used for integration testing, as it allows you to test how components interact with each other and the overall behavior of the application.

Example using Enzyme:

import { shallow, mount } from 'enzyme';
import MyComponent from './MyComponent';

// Shallow rendering
const wrapperShallow = shallow(<MyComponent />);
 
// Full DOM rendering
const wrapperMount = mount(<MyComponent />);

36. What are the best practices for structuring a React application?

Best practices for structuring a React application include:

  1. Component Organization: Organize components into folders based on functionality, grouping related components together.
  2. Use Functional Components: Prefer functional components with hooks over class components for simplicity and readability.
  3. Keep Components Small: Aim for small, reusable components that do one thing well.
  4. Use a State Management Library: Use context, Redux, or MobX for managing global state effectively.
  5. Follow Naming Conventions: Use consistent naming conventions for components, files, and folders to enhance readability.
  6. Use PropTypes or TypeScript: Validate props with PropTypes or use TypeScript for type safety.

37. How do you create a custom hook in React?

You can create a custom hook by defining a function that uses built-in hooks and returns values or functions. Custom hooks allow you to encapsulate reusable logic.

Example:

import { useState, useEffect } from 'react';

const useFetch = (url) => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err);
            }
        };

        fetchData();
    }, [url]);

    return { data, error };
};

// Usage in a component
const DataFetchingComponent = () => {
    const { data, error } = useFetch('https://api.example.com/data');

    if (error) return <div>Error: {error.message}</div>;
    if (!data) return <div>Loading...</div>;

    return <div>{JSON.stringify(data)}</div>;
};

In this example, the useFetch custom hook encapsulates the logic for fetching data and can be reused in multiple components.

38. What is the purpose of the useImperativeHandle hook?

The useImperativeHandle hook customizes the instance value that is exposed when using ref in functional components. This is useful for controlling the instance value and exposing specific methods or properties to the parent component.

Example:

import React, { useImperativeHandle, forwardRef, useRef } from 'react';

const CustomInput = forwardRef((props, ref) => {
    const inputRef = useRef();

    useImperativeHandle(ref, () => ({
        focus: () => {
            inputRef.current.focus();
        }
    }));

    return <input ref={inputRef} type="text" />;
});

// Usage in a parent component
const ParentComponent = () => {
    const inputRef = useRef();

    const handleFocus = () => {
        inputRef.current.focus();
    };

    return (
        <div>
            <CustomInput ref={inputRef} />
            <button onClick={handleFocus}>Focus Input</button>
        </div>
    );
};

In this example, useImperativeHandle allows the parent component to call the focus method defined in the child component.

39. How do you implement search functionality in a React application?

You can implement search functionality in a React application by managing search input state and filtering data based on that input.

Example:

import React, { useState } from 'react';

const SearchComponent = ({ items }) => {
    const [searchTerm, setSearchTerm] = useState('');

    const filteredItems = items.filter(item => 
        item.toLowerCase().includes(searchTerm.toLowerCase())
    );

    return (
        <div>
            <input 
                type="text" 
                placeholder="Search..." 
                value={searchTerm} 
                onChange={(e) => setSearchTerm(e.target.value)} 
            />
            <ul>
                {filteredItems.map((item, index) => (
                    <li key={index}>{item}</li>
                ))}
            </ul>
        </div>
    );
};

// Usage
const items = ['Apple', 'Banana', 'Cherry', 'Date'];
<SearchComponent items={items} />;

In this example, the search input filters a list of items based on the user's input.

40. How can you handle API errors in a React component?

You can handle API errors in a React component by using state to track the error status and displaying appropriate messages to the user.

Example:

import React, { useEffect, useState } from 'react';

const ApiComponent = () => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch('https://api.example.com/data');
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err.message);
            }
        };

        fetchData();
    }, []);

    if (error) return <div>Error: {error}</div>;
    if (!data) return <div>Loading...</div>;

    return <div>{JSON.stringify(data)}</div>;
};

In this example, errors during the fetch process are caught and stored in the error state, which is displayed to the user.

EXPERIENCE LEVEL

1. What is the virtual DOM, and how does React use it?

The virtual DOM is a lightweight representation of the actual DOM. It is a concept used by React to optimize rendering performance. Instead of directly manipulating the real DOM, which can be slow and inefficient, React first updates the virtual DOM.

When changes occur, React creates a new virtual DOM tree and compares it to the previous version using a process called diffing. After identifying what has changed, React efficiently updates only the necessary parts of the real DOM. This minimizes direct manipulations and enhances performance.

2. Explain React’s reconciliation process.

Reconciliation is the process by which React updates the UI in response to state changes. It involves the following steps:

  1. Updating the Virtual DOM: When a component's state or props change, React creates a new virtual DOM representation.
  2. Diffing: React compares the new virtual DOM with the previous one to identify changes. It uses heuristics (like comparing node types and keys) to optimize the process.
  3. Updating the Real DOM: After determining the changes, React updates only those parts of the real DOM that need to change, rather than re-rendering the entire UI.

This approach makes React efficient, as it minimizes the number of direct manipulations to the real DOM, which can be costly in terms of performance.

3. How does the shouldComponentUpdate method work?

The shouldComponentUpdate method is a lifecycle method in class components that allows developers to optimize performance. It is called before the component is re-rendered and gives a chance to control whether the component should update or not.

shouldComponentUpdate(nextProps, nextState) {
    // Return true to allow the update, false to prevent it
    return this.props.someValue !== nextProps.someValue;
}

If this method returns false, the component will not re-render, thus saving resources. This is particularly useful when you want to prevent unnecessary updates, especially in components with complex rendering logic or heavy computations.

4. What are some techniques for optimizing performance in React?

Several techniques can help optimize performance in React applications:

  1. Use React.memo: This higher-order component memoizes the result and prevents re-renders if props don’t change.
  2. Use the useCallback and useMemo hooks: These hooks help prevent unnecessary re-creation of functions and values, thus improving performance in functional components.
  3. Code Splitting: Implement lazy loading for components to reduce the initial bundle size.
  4. Avoid Inline Functions and Objects in Render: Defining functions or objects directly in the render method can cause unnecessary re-renders.
  5. Throttling and Debouncing: Use these techniques for handling events like scrolling or resizing.
  6. Use the Production Build: Always deploy the production build of React to take advantage of optimizations.

5. What is the significance of React.memo?

React.memo is a higher-order component that allows functional components to avoid unnecessary re-renders. It does this by memoizing the rendered output based on the component's props. If the props do not change, React.memo returns the memoized result instead of re-rendering the component.

const MyComponent = React.memo(({ data }) => {
    // Render logic
});

This optimization is particularly useful for components that receive the same props frequently, improving performance in applications with many components.

6. Can you explain render props and how to implement them?

Render props is a pattern for sharing code between React components using a prop whose value is a function. This function returns a React element, allowing you to create flexible and reusable components.

Example:

const DataFetcher = ({ render }) => {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('/api/data')
            .then(response => response.json())
            .then(setData);
    }, []);

    return render(data);
};

// Usage
<DataFetcher render={data => (
    <div>{data ? data.title : 'Loading...'}</div>
)} />

In this example, DataFetcher takes a render prop, allowing it to pass the fetched data back to the parent component for rendering.

7. What is the difference between useEffect and useLayoutEffect?

Both useEffect and useLayoutEffect are hooks used to perform side effects in functional components, but they differ in timing:

  • useEffect: Runs asynchronously after the DOM has been updated. This is the recommended choice for most side effects, such as fetching data or subscribing to events. It does not block the browser’s painting.
  • useLayoutEffect: Runs synchronously after all DOM mutations but before the browser has painted. Use this for side effects that need to read layout from the DOM and synchronously re-render, such as measuring DOM elements.

useEffect(() => {
    // Runs after render
}, []);

useLayoutEffect(() => {
    // Runs before the browser paint
}, []);

8. How do you manage side effects in React applications?

Side effects in React applications are typically managed using the useEffect hook in functional components and lifecycle methods (such as componentDidMount, componentDidUpdate, and componentWillUnmount) in class components.

Example using useEffect:

import React, { useEffect, useState } from 'react';

const Example = () => {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('/api/data')
            .then(response => response.json())
            .then(setData);

        return () => {
            // Cleanup logic if needed
        };
    }, []); // Dependency array

    return <div>{data ? data.title : 'Loading...'}</div>;
};

In this example, data fetching is performed as a side effect when the component mounts. The cleanup function can be used to clean up subscriptions or timers.

9. What are some common performance pitfalls in React?

Common performance pitfalls in React applications include:

  1. Unnecessary Re-renders: Not using React.memo, useMemo, or useCallback can lead to components re-rendering unnecessarily.
  2. Large Component Trees: Having too many nested components can affect performance. Breaking components into smaller pieces can help.
  3. Improper Key Usage: Using non-unique keys in lists can lead to issues with component state and performance.
  4. Heavy Computation in Render: Placing heavy computations in the render method can slow down rendering. Use memoization techniques to optimize this.
  5. Using Inline Functions in JSX: This creates a new function on every render, causing child components to re-render.

10. How can you test React components effectively?

Testing React components can be effectively done using libraries such as Jest and React Testing Library. Here are some approaches:

  1. Unit Testing: Use Jest to test the logic of individual components and their outputs based on different props or state.
  2. Integration Testing: Test how different components interact with each other, ensuring they work together as expected.
  3. Snapshot Testing: Capture the rendered output of a component at a specific time and compare it during future tests to catch unexpected changes.
  4. Simulating Events: Use React Testing Library to simulate user interactions and ensure components respond correctly.

Example using React Testing Library:

import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders MyComponent and handles click', () => {
    render(<MyComponent />);
    const button = screen.getByText('Click Me');
    fireEvent.click(button);
    expect(screen.getByText('Clicked!')).toBeInTheDocument();
});

This example tests whether a button click updates the component's state and re-renders correctly.

11. Explain the differences between useReducer and useState.

Both useReducer and useState are hooks for managing state in functional components, but they are used in different scenarios:

useState: Ideal for managing simple state variables. It allows you to manage individual pieces of state and is straightforward to use.

Example:

const [count, setCount] = useState(0);

useReducer: More suitable for complex state logic where the next state depends on the previous state. It works similarly to Redux and is beneficial when you have multiple sub-values or when the next state is computed using the previous state.

Example:

const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        default:
            throw new Error();
    }
}

const [state, dispatch] = useReducer(reducer, initialState);

12. How do you implement server-side rendering in React?

Server-side rendering (SSR) can be achieved in React using frameworks like Next.js or by using libraries like React Router with Node.js and Express.In a basic setup using Express, you can do the following:

  1. Set up a basic Express server.
  2. Render the React application on the server using renderToString from the react-dom/server package.
  3. Send the rendered HTML to the client.

Example:

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

const app = express();

app.get('/', (req, res) => {
    const html = renderToString(<App />);
    res.send(`
        <!DOCTYPE html>
        <html>
            <head>
                <title>My App</title>
            </head>
            <body>
                <div id="root">${html}</div>
                <script src="bundle.js"></script>
            </body>
        </html>
    `);
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

This approach allows the server to render the initial view, which can improve performance and SEO.

13. What is code splitting in React, and how can you implement it?

Code splitting is a technique to split your code into smaller bundles that can be loaded on demand, rather than loading the entire application at once. This improves the initial load time of your application.

You can implement code splitting in React using dynamic import() syntax and React's Suspense component.

Example:

import React, { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => (
    <div>
        <h1>My App</h1>
        <Suspense fallback={<div>Loading...</div>}>
            <LazyComponent />
        </Suspense>
    </div>
);

In this example, LazyComponent is loaded only when it is needed, and Suspense displays a fallback UI while the component is loading.

14. How do you handle authentication in a React application?

Handling authentication in a React application can involve several steps, typically including:

  1. Login Form: Create a form where users enter their credentials.
  2. API Calls: Use fetch or a library like axios to send the credentials to the server.
  3. Token Storage: On successful authentication, store the received token (e.g., JWT) in local storage or cookies.
  4. Protected Routes: Implement protected routes that check if a user is authenticated before rendering certain components.

Example:

const loginUser = async (credentials) => {
    const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials),
        headers: { 'Content-Type': 'application/json' },
    });
    const data = await response.json();
    localStorage.setItem('token', data.token); // Store the token
};

// Protected Route example
const ProtectedRoute = ({ component: Component, ...rest }) => {
    const isAuthenticated = !!localStorage.getItem('token');
    return (
        <Route 
            {...rest} 
            render={props => 
                isAuthenticated ? <Component {...props} /> : <Redirect to="/login" />
            } 
        />
    );
};

15. What are some best practices for structuring a React application?

Best practices for structuring a React application include:

  1. Component Organization: Group components logically by feature or functionality. Consider using a components folder and a separate folder for each feature.
  2. Use Functional Components: Prefer functional components over class components for cleaner, more readable code.
  3. Hooks for State and Effects: Utilize hooks like useState, useEffect, and custom hooks for managing state and side effects.
  4. Use Context API for Global State: Use React Context for managing global state rather than prop drilling.
  5. Separate Logic from UI: Use containers for logic and presentational components for UI.
  6. Naming Conventions: Use clear, descriptive names for files and components.
  7. Linting and Formatting: Use tools like ESLint and Prettier to enforce coding standards.

16. How can you create a custom hook in React?

Custom hooks are JavaScript functions that start with the word "use" and allow you to extract component logic into reusable functions.

Example of a custom hook for fetching data:

import { useState, useEffect } from 'react';

const useFetch = (url) => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                if (!response.ok) throw new Error('Network error');
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err.message);
            }
        };

        fetchData();
    }, [url]);

    return { data, error };
};

// Usage in a component
const MyComponent = () => {
    const { data, error } = useFetch('/api/data');
    return <div>{error ? error : JSON.stringify(data)}</div>;
};

17. What is the role of the useImperativeHandle hook?

The useImperativeHandle hook customizes the instance value that is exposed to parent components when using ref. This is useful when you want to expose certain functions or properties of a child component to its parent.

Example:

import React, { useImperativeHandle, forwardRef, useRef } from 'react';

const Child = forwardRef((props, ref) => {
    const inputRef = useRef();

    useImperativeHandle(ref, () => ({
        focus: () => {
            inputRef.current.focus();
        },
    }));

    return <input ref={inputRef} />;
});

// Parent Component
const Parent = () => {
    const childRef = useRef();

    const handleFocus = () => {
        childRef.current.focus();
    };

    return (
        <div>
            <Child ref={childRef} />
            <button onClick={handleFocus}>Focus Input</button>
        </div>
    );
};

In this example, the parent component can call the focus method on the child component's input field.

18. How do you handle global state in a React application?

Global state can be managed using the React Context API or state management libraries like Redux or MobX.

Using React Context API:

  1. Create Context: Create a context to hold the global state.
  2. Provider Component: Create a provider component that uses useState or useReducer to manage state and provides it to the context.
  3. Consumer Component: Use the context in child components to access and modify the global state.

Example:

import React, { createContext, useContext, useState } from 'react';

// Create Context
const GlobalStateContext = createContext();

// Provider Component
const GlobalStateProvider = ({ children }) => {
    const [state, setState] = useState({ user: null });

    return (
        <GlobalStateContext.Provider value={[state, setState]}>
            {children}
        </GlobalStateContext.Provider>
    );
};

// Consumer Hook
const useGlobalState = () => {
    return useContext(GlobalStateContext);
};

// Usage in a Component
const UserProfile = () => {
    const [state, setState] = useGlobalState();
    return <div>User: {state.user ? state.user.name : 'Guest'}</div>;
};

19. What is the purpose of the useContext hook?

The useContext hook allows functional components to subscribe to React context, making it easier to access the context value without wrapping components in a Context.Consumer. This simplifies consuming context in components.

Example:

const MyContext = createContext();

const MyComponent = () => {
    const contextValue = useContext(MyContext);
    return <div>{contextValue}</div>;
};

In this example, MyComponent can directly access the value provided by MyContext.

20. How do you ensure the security of your React application?

To ensure the security of your React application, consider the following best practices:

  1. Input Validation: Validate and sanitize user inputs to prevent XSS (Cross-Site Scripting) attacks.
  2. Avoid Inline Styles: Use CSS classes instead of inline styles to minimize the risk of injecting malicious scripts.
  3. Secure API Calls: Use HTTPS for API calls and validate the server's SSL certificate.
  4. Authentication and Authorization: Implement robust authentication and authorization mechanisms to protect sensitive routes and data.
  5. Content Security Policy (CSP): Use CSP headers to control the sources from which content can be loaded.
  6. Regular Dependency Updates: Keep your dependencies up to date to patch known vulnerabilities.
  7. Rate Limiting: Implement rate limiting on the server side to prevent abuse from bots.

21. What are the implications of using TypeScript with React?

Using TypeScript with React brings several benefits and implications:

  • Type Safety: TypeScript adds static type checking to JavaScript, helping catch errors at compile time rather than runtime. This is particularly useful for larger codebases.
  • Improved Developer Experience: With TypeScript, developers can benefit from features like autocompletion, easier refactoring, and better documentation through types.
  • Prop Types: Instead of using PropTypes for runtime type checking, TypeScript allows you to define types for props, providing compile-time checks.
  • Interfaces and Types: TypeScript allows the creation of interfaces and types, making it easier to manage complex prop shapes and state structures.
  • Learning Curve: There may be an initial learning curve for developers unfamiliar with TypeScript, but it often leads to better code quality and maintainability in the long run.
  • Integration: Integrating TypeScript into existing React projects can require some effort, especially when converting JavaScript files to TypeScript (.tsx), but it can be done incrementally.

22. How can you implement Progressive Web App (PWA) features in React?

To implement PWA features in a React application, you can follow these steps:

Create React App: If using Create React App, you can enable PWA support by changing the service worker configuration in src/index.js:

import { register } from './serviceWorkerRegistration';

register(); // Register the service worker

  1. Service Workers: Use service workers to cache assets and handle network requests. Create React App automatically sets up a service worker for you.

Manifest File: Create a manifest.json file in the public directory to define the app's name, icons, theme color, and other metadata. This file allows users to install the app on their devices.

Example: public/manifest.json

{
  "short_name": "MyApp",
  "name": "My Awesome React App",
  "icons": [
    {
      "src": "icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

  1. HTTPS: Ensure your app is served over HTTPS, as service workers only work on secure origins.
  2. Testing: Use tools like Lighthouse in Chrome DevTools to test and audit your PWA features, ensuring they meet PWA criteria.

23. What is the role of a state management library like Redux?

Redux is a popular state management library for JavaScript applications, particularly those built with React. Its main roles include:

  • Global State Management: Redux provides a centralized store that holds the application state, making it easier to manage and share data across components.
  • Predictable State Updates: State updates are made through actions and reducers, ensuring that state changes are predictable and traceable.
  • Middleware Support: Redux allows the use of middleware (like Redux Thunk or Redux Saga) for handling asynchronous actions, side effects, and logging.
  • Debugging: Redux's predictable state updates and time-travel debugging capabilities make it easier to debug applications.
  • Separation of Concerns: By separating the state management from the UI components, Redux promotes a clear structure in the application, making it easier to maintain.

24. How do you handle versioning in APIs consumed by a React application?

Handling API versioning is essential to maintain backward compatibility while updating your API. Here are common strategies:

URI Versioning: Include the version in the API endpoint URL. For example:

GET /api/v1/users

1. Header Versioning: Pass the version as a custom header in the request:

GET /api/users
Headers: { "API-Version": "1.0" }

2. Query Parameter Versioning: Use a query parameter to specify the API version:

GET /api/users?version=1

3. Backward Compatibility: When releasing a new version, ensure that the previous versions remain functional. This could involve maintaining old endpoints or providing a deprecation notice.

4. Documentation: Keep API documentation updated with the versions and changes, helping developers understand how to interact with different versions.

25. What are some common patterns for managing complex state in React?

Managing complex state in React can involve several strategies:Reducer Pattern: Use the useReducer hook to manage complex state logic, especially when the state is an object or when state transitions depend on previous states.

Example:

const initialState = { count: 0, user: null };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { ...state, count: state.count + 1 };
        case 'setUser':
            return { ...state, user: action.payload };
        default:
            return state;
    }
}

const [state, dispatch] = useReducer(reducer, initialState);

  1. Context API: Use the React Context API to provide global state management across your application, avoiding prop drilling.
  2. Custom Hooks: Create custom hooks to encapsulate complex state logic and share it across multiple components.
  3. State Management Libraries: Consider using state management libraries like Redux, MobX, or Zustand for applications with complex state needs.
  4. Memoization: Use useMemo and useCallback to optimize performance when working with complex state calculations.

26. How do you optimize images and assets in a React application?

To optimize images and assets in a React application, consider the following practices:

  1. Use Appropriate Formats: Use modern image formats like WebP or AVIF, which offer better compression without quality loss compared to JPEG or PNG.

Lazy Loading: Implement lazy loading for images and assets to improve initial load time. You can use the loading="lazy" attribute for <img> tags or a library like react-lazy-load.

Example:

<img src="image.jpg" loading="lazy" alt="Description" />

  1. Compression: Compress images using tools like ImageOptim, TinyPNG, or online services to reduce file size before adding them to your project.

Responsive Images: Use the <picture> element or srcset attribute to serve different image sizes based on the viewport size, ensuring optimal loading.

Example:

<picture>
    <source media="(min-width: 800px)" srcSet="large.jpg" />
    <img src="small.jpg" alt="Description" />
</picture>

  1. CDN: Use a Content Delivery Network (CDN) to serve static assets closer to your users, reducing load times.
  2. Webpack Optimization: Configure your build tool (like Webpack) to optimize images during the build process.

27. What is the significance of React DevTools in debugging?

React DevTools is a browser extension that provides powerful tools for debugging and inspecting React applications. Its significance includes:

  1. Component Hierarchy: View the component tree and inspect the structure of your React application, making it easier to understand how components are nested.
  2. State and Props Inspection: Examine the state and props of each component in real-time, allowing you to track down bugs related to data flow.
  3. Performance Profiling: Profile the performance of your application, identifying slow components and rendering bottlenecks. This helps optimize the app for better performance.
  4. Component Re-renders: Monitor component re-renders to understand when and why components are re-rendering, which is essential for performance optimization.
  5. Hooks Support: Inspect the state and lifecycle of React hooks directly in the DevTools, providing insight into functional components.
  6. Time-travel Debugging: Use the DevTools to go back in time and see previous states of components during development, helping to identify when a bug was introduced.

28. How do you implement WebSocket communication in a React application?

WebSocket communication allows real-time bi-directional communication between the client and server. Here’s how to implement it in a React application:Install a WebSocket Library (optional): While you can use the native WebSocket API, libraries like socket.io-client can simplify the process.
Example:

npm install socket.io-client

Establish Connection: Create a WebSocket connection in your component using useEffect to handle lifecycle events.

Example using native WebSocket API:

import React, { useEffect, useState } from 'react';

const ChatComponent = () => {
    const [messages, setMessages] = useState([]);
    const ws = new WebSocket('ws://localhost:4000');

    useEffect(() => {
        ws.onmessage = (event) => {
            setMessages((prevMessages) => [...prevMessages, event.data]);
        };

        return () => {
            ws.close(); // Cleanup on unmount
        };
    }, [ws]);

    return (
        <div>
            {messages.map((msg, index) => (
                <div key={index}>{msg}</div>
            ))}
        </div>
    );
};

Sending Messages: Create a function to send messages through the WebSocket connection.

Example:

const sendMessage = (message) => {
    ws.send(message);
};

  1. Handle Errors: Implement error handling for the WebSocket connection, using ws.onerror to handle any connection issues.
  2. Clean Up: Always ensure to close the WebSocket connection when the component unmounts to prevent memory leaks.

29. What are the benefits and challenges of using server-side rendering?

Server-side rendering (SSR) has its benefits and challenges:Benefits:

  1. Improved SEO: SSR provides fully rendered HTML to search engines, improving indexing and search visibility.
  2. Faster Initial Load: Users receive a fully rendered page, leading to a faster perceived performance on the first load.
  3. Better Performance for Slow Devices: SSR reduces the burden on client devices by handling rendering on the server, benefiting users with slower devices.
  4. Enhanced User Experience: Users see content faster, even before JavaScript is fully loaded, leading to a smoother experience.

Challenges:

  1. Increased Server Load: SSR can increase the load on the server as it handles rendering for every request, requiring more server resources.
  2. Complexity: Implementing SSR can add complexity to the application architecture and require additional configuration.
  3. Caching Strategies: Implementing effective caching strategies becomes essential to mitigate server load and improve performance.
  4. Data Fetching: Managing data fetching can be more complex in SSR, as data needs to be fetched on the server before rendering the page.

30. How do you handle cross-origin requests in React?

Handling cross-origin requests involves managing CORS (Cross-Origin Resource Sharing) in your React application. Here are some strategies:

  1. CORS Headers: Ensure the server you’re trying to access includes the appropriate CORS headers to allow requests from your domain. Common headers include:
    • Access-Control-Allow-Origin: Specifies which origins are allowed to access the resource.
    • Access-Control-Allow-Methods: Specifies the HTTP methods allowed (GET, POST, etc.).
    • Access-Control-Allow-Headers: Specifies which headers can be included in the requests.
  2. Proxying Requests: If you control the backend, set up a proxy server to forward requests from your React app to the API, effectively avoiding CORS issues.

Using Development Proxy: For local development, you can set up a proxy in your package.json file using Create React App:

"proxy": "http://localhost:5000"

  1. JSONP: For GET requests, you might use JSONP (JSON with Padding), though it's limited and not recommended for new projects.
  2. CORS Configuration: If using a service like AWS, Azure, or a custom backend, configure CORS in the server settings to allow requests from specific origins.

31. What are some strategies for enhancing accessibility in a React application?

Enhancing accessibility in a React application is essential for making it usable for all users, including those with disabilities. Here are some strategies:

  1. Semantic HTML: Use semantic HTML elements (e.g., <header>, <nav>, <main>, <footer>) to provide meaning to the content structure, which helps assistive technologies understand the layout.
  2. ARIA Roles and Attributes: Utilize ARIA (Accessible Rich Internet Applications) roles and attributes to enhance the accessibility of dynamic content. Ensure that you don’t overuse ARIA; use native HTML elements when possible.
  3. Keyboard Navigation: Ensure all interactive elements (buttons, links, forms) can be accessed and operated using keyboard navigation. Manage focus appropriately when components mount or update.
  4. Alt Text for Images: Always provide descriptive alt text for images, allowing screen readers to convey the content or function of images.
  5. Focus Management: Implement focus management to guide users when navigating between different components, especially in modals and pop-ups.
  6. Color Contrast: Ensure sufficient color contrast between text and background to improve readability for users with visual impairments.
  7. Testing Tools: Use accessibility testing tools like Axe, Lighthouse, or WAVE to evaluate your application and identify accessibility issues.
  8. User Testing: Conduct user testing with individuals who have disabilities to gather feedback on accessibility and make necessary improvements.

32. How do you perform integration testing for React applications?

Integration testing for React applications focuses on testing how components work together. Here are the steps and best practices:

  1. Testing Library: Use a testing library like React Testing Library or Enzyme, which allows you to simulate user interactions and test component integration.
  2. Setup Test Environment: Ensure your testing environment is properly set up with Jest or another testing framework compatible with your library.

Render Components: Render components with the necessary context and props. Use utility functions to wrap components that require providers (like Redux or Context API).
Example using React Testing Library:

import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import store from './store';
import MyComponent from './MyComponent';

test('renders MyComponent', () => {
    render(
        <Provider store={store}>
            <MyComponent />
        </Provider>
    );
    expect(screen.getByText(/some text/i)).toBeInTheDocument();
});

Simulate User Interactions: Use fireEvent or user-event to simulate user interactions like clicks, typing, and other events, and assert the expected outcomes.

Example:

import userEvent from '@testing-library/user-event';

test('clicking the button updates the count', () => {
    render(<MyComponent />);
    userEvent.click(screen.getByRole('button'));
    expect(screen.getByText(/count: 1/i)).toBeInTheDocument();
});

  1. Mocking API Calls: Use libraries like msw (Mock Service Worker) or jest.mock to mock API calls and control responses during tests.
  2. Assertions: Make assertions to ensure components behave as expected when integrated with one another, checking for changes in state, rendering of elements, and function calls.

33. What is the role of useEffect in data fetching?

The useEffect hook is essential for managing side effects in functional components, including data fetching. Here’s its role in this context:

  1. Side Effects Management: useEffect allows you to perform side effects (like fetching data) in a functional component without affecting the component's rendering.

Dependency Array: By passing a dependency array as the second argument to useEffect, you can control when the effect runs. For example, if you want to fetch data when the component mounts, you can provide an empty array:

useEffect(() => {
    fetchData();
}, []); // Runs only on mount

Cleanup Function: If the effect involves setting up subscriptions or intervals, you can return a cleanup function to prevent memory leaks:

useEffect(() => {
    const subscription = subscribeToData();

    return () => {
        subscription.unsubscribe(); // Cleanup
    };
}, []);

Handling Async Operations: Since useEffect cannot return a promise directly, you can define an async function within it or use an IIFE (Immediately Invoked Function Expression) to handle async data fetching:

useEffect(() => {
    const fetchData = async () => {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        setData(data);
    };

    fetchData();
}, []);

  1. Managing State Updates: When the fetched data is received, you can update the component’s state, triggering a re-render with the new data.

34. How do you implement caching in a React application?

Implementing caching in a React application can improve performance by reducing unnecessary network requests. Here are some strategies:

Local Storage: Use the browser’s local storage or session storage to cache data fetched from APIs. This allows you to persist data across sessions.

Example:

const fetchData = async () => {
    const cachedData = localStorage.getItem('myData');

    if (cachedData) {
        setData(JSON.parse(cachedData));
    } else {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        setData(data);
        localStorage.setItem('myData', JSON.stringify(data));
    }
};

Service Workers: Use service workers to cache API responses for offline access and improve load times.

React Query: Consider using libraries like React Query or SWR, which provide built-in caching mechanisms and handle data fetching, updating, and caching out of the box.

Example with React Query:

import { useQuery } from 'react-query';

const { data, error } = useQuery('myData', fetchData);

  1. Memoization: Use memoization techniques with useMemo and useCallback to cache the results of expensive calculations or data transformations.
  2. GraphQL Client Caching: If using GraphQL, libraries like Apollo Client come with built-in caching mechanisms to manage query results efficiently.

35. What are the benefits of using component libraries in React?

Using component libraries in React offers several benefits:

  1. Speed of Development: Pre-built components reduce the time spent on development, allowing teams to focus on business logic and features rather than UI design.
  2. Consistency: Component libraries enforce design consistency across applications, helping maintain a unified look and feel.
  3. Accessibility: Many component libraries prioritize accessibility, providing components that are already optimized for use with assistive technologies.
  4. Responsive Design: Libraries often include responsive design principles, ensuring components work well on different devices and screen sizes.
  5. Customizability: Most libraries allow for customization and theming, enabling developers to tailor components to fit specific branding and design requirements.
  6. Community and Support: Popular component libraries have large communities, providing extensive documentation, resources, and community support for troubleshooting.
  7. Performance Optimization: Many libraries are optimized for performance, using techniques like tree shaking to minimize bundle size.

36. How do you manage performance in large-scale React applications?

Managing performance in large-scale React applications involves several strategies:

  1. Code Splitting: Use code splitting to load only the necessary code for each page, reducing initial load times. React supports dynamic imports, which can be implemented with React.lazy.
  2. Memoization: Use React.memo, useMemo, and useCallback to prevent unnecessary re-renders and optimize performance for components and functions.
  3. Virtualization: Implement virtualization techniques for rendering large lists or tables, using libraries like react-window or react-virtualized to render only visible items.
  4. Efficient State Management: Use appropriate state management solutions (like Redux or Context API) to minimize unnecessary re-renders by managing state effectively.
  5. Avoid Inline Functions and Objects: Avoid creating inline functions and objects within render methods, as they can lead to unnecessary re-renders.
  6. Performance Monitoring: Utilize performance monitoring tools (like Lighthouse or React Profiler) to identify bottlenecks and areas for improvement.
  7. Optimize Images and Assets: Use optimized image formats and lazy loading to enhance loading times and performance.
  8. Server-Side Rendering: Consider SSR to improve initial load performance by rendering content on the server.

37. How do you implement responsive design in a React application?

To implement responsive design in a React application, you can follow these practices:

  1. CSS Flexbox and Grid: Utilize CSS Flexbox and Grid layouts to create flexible and adaptive designs that adjust based on the viewport size.

Media Queries: Use CSS media queries to apply different styles at various breakpoints, allowing you to adapt layouts for different screen sizes.
Example:

@media (max-width: 600px) {
    .container {
        flex-direction: column;
    }
}

  1. Responsive Units: Use relative units like percentages, em, or rem for widths, heights, and font sizes instead of fixed units like pixels.
  2. CSS Frameworks: Consider using responsive CSS frameworks like Bootstrap or Material-UI, which provide built-in responsive components and grid systems.
  3. Viewport Units: Utilize viewport units (vw, vh) for sizing elements relative to the viewport dimensions.
  4. Mobile-First Approach: Design your styles with a mobile-first approach, applying styles for smaller screens first and then layering on additional styles for larger screens using media queries.
  5. Responsive Images: Use the srcset attribute or <picture> element to serve different image sizes based on the device’s screen resolution and size.

38. How do you ensure your React application is SEO-friendly?

Ensuring your React application is SEO-friendly can involve several strategies:

  1. Server-Side Rendering (SSR): Use SSR to generate fully rendered HTML pages on the server, making it easier for search engines to index your content.
  2. React Helmet: Use libraries like React Helmet to manage changes to the document head, allowing you to set meta tags, titles, and descriptions dynamically for each page.
  3. Sitemap and Robots.txt: Create a sitemap and robots.txt file to guide search engines on how to crawl your site.
  4. Semantic HTML: Use semantic HTML tags to give meaning to the content, helping search engines understand the structure and importance of elements.
  5. Accessible Links: Ensure that all links are crawlable and not hidden behind JavaScript actions. Use meaningful anchor text for links.
  6. Optimized Images: Use descriptive alt attributes for images to enhance accessibility and provide context for search engines.
  7. Content Quality: Focus on high-quality, relevant content that engages users and encourages backlinks, which improves SEO rankings.
  8. Performance Optimization: Improve page load speed and performance, as slow-loading sites can negatively impact SEO.

39. How do you manage dependencies in a React project?

Managing dependencies in a React project involves several best practices:

  1. Package Manager: Use a package manager like npm or Yarn to manage dependencies and their versions.
  2. Version Control: Specify exact versions or version ranges in package.json to ensure consistent installations across environments. Use semantic versioning (semver) principles.
  3. Regular Updates: Regularly update dependencies to incorporate security patches, bug fixes, and new features. Use tools like npm outdated or npm-check-updates to track outdated dependencies.
  4. Lock Files: Use lock files (package-lock.json for npm or yarn.lock for Yarn) to ensure consistent dependency versions across different environments and installations.
  5. Peer Dependencies: Be mindful of peer dependencies when using component libraries, ensuring that the required versions of React and other libraries are installed.
  6. Remove Unused Dependencies: Regularly audit your project for unused dependencies and remove them to keep the project lean and reduce potential security vulnerabilities.
  7. Documentation: Keep documentation updated for any custom or internal dependencies, ensuring other developers understand how to use them.

40. What are some future trends you see in the React ecosystem?

Future trends in the React ecosystem may include:

  1. React Server Components: The ongoing development of React Server Components aims to enhance server-rendered applications, improving performance and reducing client-side bundle sizes.
  2. Concurrent Features: React's concurrent features will likely become more prominent, enabling smoother user experiences by prioritizing updates and rendering.
  3. Improved Data Fetching: Libraries like React Query and SWR are gaining popularity for efficient data fetching and caching, which will continue to evolve.
  4. TypeScript Adoption: The adoption of TypeScript in the React ecosystem is expected to grow, providing enhanced type safety and developer experience.
  5. Micro-frontend Architecture: The micro-frontend architecture will become more prevalent, allowing teams to build and deploy parts of an application independently.
  6. Static Site Generation (SSG): The popularity of static site generation will increase, especially with frameworks like Next.js making it easier to create fast and SEO-friendly applications.
  7. Improved Tooling: Enhanced tooling and debugging capabilities will continue to evolve, helping developers build and maintain React applications more efficiently.
  8. Focus on Accessibility: There will be an increasing emphasis on building accessible applications, with improved tools and practices being adopted.

These trends indicate that the React ecosystem is continuously evolving to meet the needs of developers and users, making it an exciting space to watch and participate in.

WeCP Team
Team @WeCP
WeCP is a leading talent assessment platform that helps companies streamline their recruitment and L&D process by evaluating candidates' skills through tailored assessments