Interview

30 ReactJS Interview Questions and Answers

Prepare for your next interview with this guide on ReactJS, featuring common questions and answers to help you demonstrate your expertise.

ReactJS has become a cornerstone in modern web development, known for its efficiency in building dynamic and responsive user interfaces. Its component-based architecture allows developers to create reusable UI components, making code more maintainable and scalable. With a strong community and extensive ecosystem, ReactJS continues to evolve, offering robust solutions for both small and large-scale applications.

This article provides a curated selection of interview questions designed to test your understanding and proficiency in ReactJS. By working through these questions and their detailed answers, you will gain deeper insights into key concepts and best practices, helping you to confidently tackle technical interviews and demonstrate your expertise.

ReactJS Interview Questions and Answers

1. What is JSX and why is it used?

JSX stands for JavaScript XML. It is a syntax extension for JavaScript that allows developers to write HTML-like code within JavaScript. This makes it easier to create and visualize the structure of the user interface in React applications. JSX is not a requirement for using React, but it is widely adopted because it simplifies the process of writing components and improves code readability.

JSX allows you to write elements and components in a way that closely resembles HTML, which can make the code more intuitive and easier to understand. Under the hood, JSX is transformed into JavaScript function calls that create React elements. This transformation is typically handled by a build tool like Babel.

Example:

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

In this example, the JSX syntax <h1>Hello, world!</h1> is transformed into a JavaScript function call that creates a React element. This makes it easier to write and maintain the user interface code.

2. How do you handle events in React?

In React, handling events is similar to handling events in plain JavaScript, but with some syntactic differences. React events are named using camelCase, rather than lowercase. Additionally, in JSX, you pass a function as the event handler, rather than a string.

Example:

import React, { Component } from 'react';

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

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

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

export default MyComponent;

In this example, the handleClick method is bound to the component instance in the constructor. The onClick event is attached to the button element, and when the button is clicked, the handleClick method is invoked, updating the component’s state.

3. What are hooks and why are they important?

Hooks are functions that let you “hook into” React state and lifecycle features from function components. They provide a more direct API to the React concepts you already know, such as state, lifecycle, context, refs, and more.

The most commonly used hooks are:

  • useState: Allows you to add state to functional components.
  • useEffect: Lets you perform side effects in function components.
  • useContext: Provides a way to access the context API.

Example:

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example, useState is used to declare a state variable count, and useEffect is used to perform a side effect (updating the document title) whenever the count changes.

4. Write a useState hook to manage a counter.

In React, 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. This hook is particularly useful for managing simple stateful logic, such as a counter.

Example:

import React, { useState } from 'react';

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

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

export default Counter;

In this example, the useState hook is used to create a state variable named count and a function named setCount to update the count. The initial state is set to 0. The component renders the current count and two buttons to increment and decrement the count.

5. How do you pass data between components?

In React, data can be passed between components using several methods:

  • Props: The most common way to pass data from a parent component to a child component is through props. Props are read-only and allow you to pass data and event handlers down the component tree.
  • Callback Functions: To pass data from a child component to a parent component, you can use callback functions. The parent component passes a function as a prop to the child component, and the child component calls this function to send data back to the parent.
  • Context: For more complex scenarios where data needs to be shared across multiple components without prop drilling, React’s Context API can be used. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

Example:

// Parent Component
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
    const [data, setData] = useState('Initial Data');

    const handleDataChange = (newData) => {
        setData(newData);
    };

    return (
        <div>
            <h1>Parent Component</h1>
            <p>Data: {data}</p>
            <ChildComponent onDataChange={handleDataChange} />
        </div>
    );
};

export default ParentComponent;

// Child Component
import React from 'react';

const ChildComponent = ({ onDataChange }) => {
    const changeData = () => {
        onDataChange('New Data from Child');
    };

    return (
        <div>
            <h2>Child Component</h2>
            <button onClick={changeData}>Change Data</button>
        </div>
    );
};

export default ChildComponent;

6. How do you fetch data from an API in a functional component?

In React, data fetching in a functional component is typically done using the useEffect hook along with the fetch API. The useEffect hook allows you to perform side effects in your components, such as fetching data from an API. The fetch API is used to make network requests to retrieve data.

Here is a concise example:

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

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

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch('https://api.example.com/data');
                const result = await response.json();
                setData(result);
            } catch (error) {
                console.error('Error fetching data:', error);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, []);

    if (loading) {
        return <div>Loading...</div>;
    }

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

export default DataFetchingComponent;

7. What is Context API and when would you use it?

The Context API in React provides a way to share values between components without having to explicitly pass a prop through every level of the tree. It is designed to solve the problem of prop drilling, where you have to pass data through many layers of components that do not need it, just to get it to the one component that does.

To use the Context API, you create a context using React.createContext(), then use a Provider component to pass the data down the tree, and a Consumer component or the useContext hook to access the data in any component.

Example:

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

// Create a Context
const ThemeContext = createContext();

// Create a Provider component
const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light');
    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    );
};

// Create a component that uses the Context
const ThemedComponent = () => {
    const { theme, setTheme } = useContext(ThemeContext);
    return (
        <div>
            <p>Current theme: {theme}</p>
            <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
                Toggle Theme
            </button>
        </div>
    );
};

// Use the Provider in your app
const App = () => (
    <ThemeProvider>
        <ThemedComponent />
    </ThemeProvider>
);

export default App;

8. Implement a simple context provider and consumer.

To implement a simple context provider and consumer in React, you can use the createContext and useContext hooks. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

Example:

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

// Create a Context
const MyContext = createContext();

// Create a Provider component
const MyProvider = ({ children }) => {
    const [value, setValue] = useState('Hello, World!');
    
    return (
        <MyContext.Provider value={{ value, setValue }}>
            {children}
        </MyContext.Provider>
    );
};

// Create a Consumer component
const MyConsumer = () => {
    const { value, setValue } = useContext(MyContext);
    
    return (
        <div>
            <p>{value}</p>
            <button onClick={() => setValue('Hello, React!')}>Change Value</button>
        </div>
    );
};

// Main App component
const App = () => (
    <MyProvider>
        <MyConsumer />
    </MyProvider>
);

export default App;

9. How do you optimize performance in a React application?

To optimize performance in a React application, several strategies can be employed:

  • Code Splitting: This involves breaking down the application into smaller chunks that can be loaded on demand. This reduces the initial load time and improves performance. Tools like Webpack can be used for code splitting.
  • Memoization: Using React’s memo and useMemo hooks can help prevent unnecessary re-renders by memoizing the results of expensive calculations or components that do not need to re-render on every update.
  • Virtualization: Libraries like React Virtualized or React Window can be used to render only the visible items in a list, which significantly improves performance when dealing with large datasets.
  • Avoiding Inline Functions: Inline functions can cause unnecessary re-renders. Instead, define functions outside of the render method or use the useCallback hook to memoize them.
  • Optimizing State Management: Ensure that state is lifted up appropriately and avoid unnecessary state updates. Using libraries like Redux or Context API can help manage state more efficiently.
  • Lazy Loading: Components that are not immediately needed can be loaded lazily using React’s lazy and Suspense to improve the initial load time.
  • Using PureComponent: Extending React.PureComponent instead of React.Component can help avoid re-renders when the props and state have not changed.
  • Profiling and Monitoring: Use React’s built-in Profiler API and tools like React DevTools to identify performance bottlenecks and optimize them accordingly.

10. What is the purpose of keys in lists?

In React, keys are used to help identify which items in a list have changed, been added, or removed. This is essential for optimizing the rendering process and ensuring that the UI updates efficiently. When rendering a list of elements, each element should have a unique key to help React keep track of changes.

Example:

import React from 'react';

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

const items = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
  { id: 3, name: 'Item 3' }
];

function App() {
  return <ItemList items={items} />;
}

export default App;

In this example, each list item is given a unique key based on its id. This helps React efficiently update the list when items are added, removed, or changed.

11. How do you handle forms in React?

Handling forms in React typically involves using controlled components, where the form data is handled by the component’s state. This allows for more control over the form data and makes it easier to perform validation and other operations.

Example:

import React, { useState } from 'react';

function MyForm() {
    const [formData, setFormData] = useState({
        name: '',
        email: ''
    });

    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData({
            ...formData,
            [name]: value
        });
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        console.log('Form data submitted:', formData);
    };

    return (
        <form onSubmit={handleSubmit}>
            <label>
                Name:
                <input type="text" name="name" value={formData.name} onChange={handleChange} />
            </label>
            <br />
            <label>
                Email:
                <input type="email" name="email" value={formData.email} onChange={handleChange} />
            </label>
            <br />
            <button type="submit">Submit</button>
        </form>
    );
}

export default MyForm;

12. What is PropTypes and how do you use it?

PropTypes is a library in React that allows developers to specify the types of props that a component should receive. This helps in validating the props and catching potential bugs during development. PropTypes can check for various data types such as strings, numbers, arrays, objects, and even custom types.

Example:

import React from 'react';
import PropTypes from 'prop-types';

class MyComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <p>{this.props.description}</p>
      </div>
    );
  }
}

MyComponent.propTypes = {
  title: PropTypes.string.isRequired,
  description: PropTypes.string
};

export default MyComponent;

In this example, the MyComponent class has two props: title and description. The propTypes property is used to specify that title should be a string and is required, while description should be a string but is optional.

13. What are render props and how do you use them?

Render props are a pattern in React that allows a component to share logic with other components using a prop whose value is a function. This function returns a React element and can be used to pass data to the child component. Render props are useful for creating reusable and flexible components that can adapt to different use cases.

Example:

import React from 'react';

class DataFetcher extends React.Component {
  state = { data: null };

  componentDidMount() {
    fetch(this.props.url)
      .then(response => response.json())
      .then(data => this.setState({ data }));
  }

  render() {
    return this.props.render(this.state.data);
  }
}

const App = () => (
  <DataFetcher url="https://api.example.com/data" render={data => (
    <div>
      {data ? data.map(item => <div key={item.id}>{item.name}</div>) : 'Loading...'}
    </div>
  )} />
);

export default App;

In this example, the DataFetcher component fetches data from a given URL and uses a render prop to pass the fetched data to the child component. The App component uses the DataFetcher and provides a function to render the data.

14. Implement a custom hook for fetching data.

Custom hooks in React allow you to extract and reuse logic across multiple components. They are JavaScript functions that start with “use” and can call other hooks. Custom hooks help in keeping the code clean and DRY (Don’t Repeat Yourself).

Here is an example of a custom hook for fetching data:

import { useState, useEffect } from 'react';

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

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

        fetchData();
    }, [url]);

    return { data, loading, error };
};

export default useFetch;

15. How do you handle error boundaries in React?

Error boundaries in React are implemented using class components. A class component becomes an error boundary by defining either or both of the lifecycle methods static getDerivedStateFromError() and componentDidCatch().

Here is an example of how to implement an error boundary:

import React, { Component } from 'react';

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

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    console.log(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

export default ErrorBoundary;

To use this error boundary, you would wrap it around any component that you want to monitor for errors:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

16. How do you implement lazy loading in React?

Lazy loading in React is a technique used to defer the loading of components until they are needed. This can significantly improve the performance of a React application by reducing the initial load time. React provides built-in support for lazy loading through the React.lazy function and the Suspense component.

Example:

import React, { Suspense } from 'react';

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

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

export default App;

In this example, the LazyComponent is only loaded when it is needed, and a fallback UI (a loading message) is displayed while the component is being loaded.

17. What is Redux and how does it work with React?

Redux is a state management library that provides a centralized store for all the state in an application. It works on the principles of having a single source of truth, making the state predictable and easier to debug. Redux is often used with React to manage the state of an application in a more structured and maintainable way.

In a typical React application, state is managed within components. As the application grows, managing state across multiple components can become challenging. Redux addresses this issue by providing a single store for the entire application state. Components can then access the state from this store, making state management more predictable and easier to debug.

Redux works with three core principles:

  • Single Source of Truth: The state of the entire application is stored in a single object within a single store.
  • State is Read-Only: The only way to change the state is to emit an action, an object describing what happened.
  • Changes are Made with Pure Functions: To specify how the state tree is transformed by actions, you write pure reducers.

Here is a simple example to demonstrate how Redux works with React:

import { createStore } from 'redux';
import { Provider, useDispatch, useSelector } from 'react-redux';

// Action
const increment = () => ({ type: 'INCREMENT' });

// Reducer
const counter = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    default:
      return state;
  }
};

// Store
const store = createStore(counter);

const Counter = () => {
  const dispatch = useDispatch();
  const count = useSelector(state => state);

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

const App = () => (
  <Provider store={store}>
    <Counter />
  </Provider>
);

In this example, we create a Redux store with a simple counter reducer. The Counter component uses useDispatch to dispatch the increment action and useSelector to read the current state from the store. The App component wraps the Counter component with the Provider component, passing the store as a prop.

18. Set up a basic Redux store and connect it to a component.

Redux is a state management library often used with React to manage the state of an application in a predictable way. It helps in maintaining a single source of truth for the state, making it easier to debug and test.

To set up a basic Redux store and connect it to a React component, follow these steps:

  • Create a Redux store.
  • Define a reducer to manage the state.
  • Use the Provider component to make the store available to the React application.
  • Connect a React component to the Redux store using the connect function from react-redux.

Example:

// Step 1: Create a Redux store
import { createStore } from 'redux';
import { Provider, connect } from 'react-redux';
import React from 'react';
import ReactDOM from 'react-dom';

// Step 2: Define a reducer
const initialState = { count: 0 };

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
}

const store = createStore(counterReducer);

// Step 3: Create a React component
function Counter({ count, increment }) {
  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

// Step 4: Connect the component to the Redux store
const mapStateToProps = state => ({ count: state.count });
const mapDispatchToProps = dispatch => ({
  increment: () => dispatch({ type: 'INCREMENT' })
});

const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);

// Render the application
ReactDOM.render(
  <Provider store={store}>
    <ConnectedCounter />
  </Provider>,
  document.getElementById('root')
);

19. How do you use React Router for navigation?

React Router is used to handle navigation in a React application. It allows you to define multiple routes in your application and navigate between them. The core components of React Router are BrowserRouter, Route, Switch, and Link.

Example:

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const Contact = () => <h2>Contact</h2>;

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/contact">
            <Contact />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

In this example, BrowserRouter is used to wrap the entire application, enabling routing. The Route component is used to define individual routes, and the Switch component is used to render only the first route that matches the current URL. The Link component is used to create navigation links.

20. What are fragments and why are they useful?

Fragments in React allow you to group a list of children without adding extra nodes to the DOM. This is useful for maintaining a clean and efficient DOM structure, especially when you need to return multiple elements from a component’s render method.

Using fragments can help avoid unnecessary wrapper elements, which can clutter the DOM and potentially cause styling issues. React provides two ways to use fragments: the shorthand syntax and the longhand syntax.

Example:

import React from 'react';

function ListItems() {
  return (
    <>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </>
  );
}

export default ListItems;

In the example above, the shorthand syntax <> is used to wrap the list items without adding an extra node to the DOM. This keeps the DOM clean and efficient.

Alternatively, you can use the longhand syntax:

import React from 'react';

function ListItems() {
  return (
    <React.Fragment>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </React.Fragment>
  );
}

export default ListItems;

21. How do you memoize a component to prevent unnecessary re-renders?

Memoization in React is a technique used to optimize performance by preventing unnecessary re-renders of components. This is particularly useful in scenarios where components are expensive to render or when the same component is rendered multiple times with the same props. React provides two main tools for memoization: React.memo and the useMemo hook.

React.memo is a higher-order component that memoizes the result of a component rendering. It only re-renders the component if its props have changed. The useMemo hook, on the other hand, memoizes the result of a function call, ensuring that the function is only re-executed when its dependencies change.

Example using React.memo:

import React from 'react';

const MyComponent = React.memo(({ value }) => {
  console.log('Rendering MyComponent');
  return <div>{value}</div>;
});

export default MyComponent;

Example using useMemo:

import React, { useMemo } from 'react';

const MyComponent = ({ value }) => {
  const memoizedValue = useMemo(() => {
    console.log('Calculating memoized value');
    return value * 2;
  }, [value]);

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

export default MyComponent;

22. What is the difference between useEffect and useLayoutEffect?

In React, both useEffect and useLayoutEffect are hooks that allow you to perform side effects in function components. However, they differ in terms of when they are executed in the component lifecycle.

  • useEffect: This hook is executed after the render is committed to the screen. It is useful for operations that do not require blocking the browser’s painting, such as fetching data, setting up subscriptions, or manually changing the DOM.
  • useLayoutEffect: This hook is executed synchronously after all DOM mutations but before the browser has a chance to paint. It is useful for operations that need to read the layout from the DOM and synchronously re-render.

Example:

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

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

    useEffect(() => {
        console.log('useEffect - after render');
    }, [count]);

    useLayoutEffect(() => {
        console.log('useLayoutEffect - before paint');
    }, [count]);

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

In this example, when the button is clicked, useLayoutEffect will log its message before the browser paints the updated count, while useEffect will log its message after the render is committed to the screen.

23. Implement a component that uses useReducer for state management.

The useReducer hook in React is used for managing state in components where the state logic is complex and involves multiple sub-values or when the next state depends on the previous one. It is an alternative to useState and is more suited for scenarios where state transitions are more intricate.

Here is an example of a simple counter component that uses useReducer for state management:

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();
  }
}

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

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

export default Counter;

In this example, the reducer function handles the state transitions based on the action type. The Counter component uses the useReducer hook to manage its state, and the dispatch function is used to send actions to the reducer.

24. How do you test a React component using Jest?

Testing a React component using Jest involves setting up Jest as the testing framework, writing test cases, and using Jest functions to assert the expected behavior of the component. Jest is a popular testing framework for JavaScript applications, and it works seamlessly with React.

First, ensure that Jest is installed in your project. You can install it using npm or yarn:

npm install --save-dev jest

Next, create a test file for your React component. Jest conventionally looks for files with the .test.js or .spec.js extension.

Here is a simple example of a React component and its corresponding test using Jest:

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

const MyComponent = ({ text }) => {
  return <div>{text}</div>;
};

export default MyComponent;
// MyComponent.test.js
import React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders the correct text', () => {
  const { getByText } = render(<MyComponent text="Hello, World!" />);
  expect(getByText('Hello, World!')).toBeInTheDocument();
});

In this example, the MyComponent component is a simple functional component that displays a text prop. The test file MyComponent.test.js uses the render function from @testing-library/react to render the component and then asserts that the text “Hello, World!” is present in the document using Jest’s expect function.

25. What is the significance of React Fiber?

React Fiber is a reimplementation of the React core algorithm, aimed at improving the performance and responsiveness of React applications. The primary goals of React Fiber include:

  • Incremental Rendering: React Fiber allows for the rendering work to be split into chunks and spread out over multiple frames. This makes it possible to pause and resume work, which is particularly useful for complex applications that require smooth user interactions.
  • Prioritization: React Fiber introduces the concept of priority levels, enabling the framework to prioritize updates based on their importance. This ensures that high-priority updates, such as user input, are handled before less critical updates.
  • Concurrency: React Fiber supports concurrent rendering, allowing multiple tasks to be processed simultaneously. This improves the overall performance and responsiveness of the application.
  • Better Error Handling: React Fiber provides improved error boundaries, making it easier to catch and handle errors in the component tree.

26. How do you handle side effects in a React application?

In React, side effects are typically handled using the useEffect hook. The useEffect hook allows you to perform side effects in function components. It takes two arguments: a function that contains the side-effect logic and an optional array of dependencies that determine when the effect should be re-run.

Example:

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

function DataFetchingComponent() {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => setData(data))
            .catch(error => setError(error));
    }, []); // Empty array means this effect runs once after the initial render

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

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

    return (
        <div>
            <h1>Data</h1>
            <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
    );
}

export default DataFetchingComponent;

27. What are portals in React and when would you use them?

Portals in React provide a way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. This is particularly useful for scenarios where you need to visually break out of the parent component’s container, such as modals, tooltips, or dropdowns.

To create a portal, you use the ReactDOM.createPortal method, which takes two arguments: the JSX to render and the DOM node to render it into.

Example:

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

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }

  componentDidMount() {
    document.body.appendChild(this.el);
  }

  componentWillUnmount() {
    document.body.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(
      this.props.children,
      this.el
    );
  }
}

function App() {
  return (
    <div>
      <h1>My App</h1>
      <Modal>
        <div className="modal">
          <p>This is a modal!</p>
        </div>
      </Modal>
    </div>
  );
}

In this example, the Modal component uses a portal to render its children into a new div element appended to the document.body. This allows the modal to appear outside the normal DOM hierarchy of the App component.

28. Discuss various performance optimization techniques in React.

Performance optimization in React can be achieved through several techniques:

  • Memoization: Using React.memo to prevent unnecessary re-renders of functional components.
  • Code Splitting: Using dynamic import() to split code into smaller bundles that can be loaded on demand.
  • Lazy Loading: Using React.lazy and Suspense to load components only when they are needed.
  • Use of PureComponent: Extending React.PureComponent to automatically implement shouldComponentUpdate with a shallow prop and state comparison.
  • Virtualization: Using libraries like react-window or react-virtualized to efficiently render large lists.
  • Optimizing State Management: Keeping state local where necessary and using Context API or libraries like Redux efficiently.
  • Event Handling: Using event delegation and avoiding inline functions in render methods.

Example of using React.memo:

import React, { memo } from 'react';

const MyComponent = ({ data }) => {
  console.log('Rendering MyComponent');
  return <div>{data}</div>;
};

export default memo(MyComponent);

29. How do you ensure accessibility in a React application?

Ensuring accessibility in a React application involves several best practices and tools. Here are some key strategies:

  • Semantic HTML: Use semantic HTML elements like <header>, <nav>, <main>, and <footer> to provide meaningful structure to your content.
  • ARIA Roles: Use ARIA (Accessible Rich Internet Applications) roles and attributes to enhance the accessibility of dynamic content. For example, use role="button" for interactive elements that are not buttons.
  • Keyboard Navigation: Ensure that all interactive elements are accessible via keyboard. This includes using tabindex and handling keyboard events.
  • Accessible Forms: Use <label> elements for form controls and ensure that each form element has an associated label.
  • Color Contrast: Ensure sufficient color contrast between text and background to make content readable for users with visual impairments.
  • Accessibility Testing: Use tools like aXe, Lighthouse, and React’s accessibility libraries to test and improve the accessibility of your application.

Example:

import React from 'react';

const AccessibleButton = () => {
  return (
    <button aria-label="Close" onClick={() => alert('Button clicked!')}>
      Close
    </button>
  );
};

export default AccessibleButton;

30. What are some common testing strategies in React?

Common testing strategies in React include unit testing, integration testing, and end-to-end testing. Each of these strategies serves a different purpose and helps ensure the reliability and functionality of React applications.

  • Unit Testing: This involves testing individual components or functions in isolation. Tools like Jest and Enzyme are commonly used for unit testing in React. Jest is a JavaScript testing framework, while Enzyme is a testing utility for React that makes it easier to test the output of React components.

    Example:

    javascript import React from 'react'; import { shallow } from 'enzyme'; import MyComponent from './MyComponent'; describe('MyComponent', () => { it('should render correctly', () => { const wrapper = shallow(<MyComponent />); expect(wrapper).toMatchSnapshot(); }); });

  • Integration Testing: This type of testing focuses on the interaction between different components or modules. It ensures that combined parts of the application work together as expected. Tools like React Testing Library are often used for integration testing.
  • End-to-End (E2E) Testing: E2E testing simulates real user interactions and tests the entire application flow from start to finish. Tools like Cypress and Selenium are popular for E2E testing in React applications. These tools help automate browser actions and verify that the application behaves correctly in a real-world scenario.
Previous

10 WebFlux Interview Questions and Answers

Back to Interview