Most Commonly Asked React Interview Questions 2024 - Part 3
Sayuj Sehgal
Posted on March 15, 2024
If you like this blog, you can visit my personal blog sehgaltech for more content.
1. How do you handle error boundaries in React?
Error boundaries in React are a way to catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.
Here's an example of how you can define an error boundary:
class ErrorBoundary extends React.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, info) {
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
You can use it as a regular component:
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
In the above example, if MyComponent
or any of its children throw an error during rendering, the error will be caught by the ErrorBoundary
, the fallback UI will be rendered, and the error will be logged.
Please note that error boundaries only catch errors in the components below them in the tree. An error boundary canโt catch an error within itself.
2. What is the use of refs in React?
Refs in React are used to access and interact with DOM nodes or React elements directly. They are used in cases where you need to imperatively modify a child outside of the typical data flow. Here are a few common use cases for refs:
- Managing focus, text selection, or media playback.
- Triggering imperative animations.
- Integrating with third-party DOM libraries.
In functional components, refs are used with the useRef
hook. Here's an example of how to use refs to manage focus on an input element in a functional component:
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const myRef = useRef(null);
useEffect(() => {
myRef.current.focus();
}, []);
return <input ref={myRef} />;
}
In this example, myRef
is a reference to the DOM node rendered by the <input />
element, so it can be used to access the properties and methods of this node.
It's important to note that you should avoid using refs for anything that can be done declaratively. For example, instead of using a ref to expose text content of a <span>
, you should pass it as a prop.
3. How do you manage side effects in React?
In React, side effects are managed using a built-in hook called useEffect
. Side effects are operations that can affect other components and can't be done during rendering. These include data fetching, subscriptions, or manually changing the DOM.
The useEffect
hook accepts two arguments: a function where you can perform your side effects, and an array of dependencies. The function will run after the render is committed to the screen.
If you pass an empty array ([]
) as the second argument, the side effect runs once after the initial render, similar to componentDidMount
in class components. If you pass variables in the array, the side effect will run whenever any of those variables change, similar to componentDidUpdate
.
Here's an example of using useEffect
to fetch data from an API:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []); // Empty array means this effect runs once after initial render
return (
<div>
{data ? `Data: ${data}` : 'Loading...'}
</div>
);
}
In this example, the useEffect
hook fetches data from an API and updates the component's state with the fetched data. The empty array ([]
) means the data fetching happens once after the component mounts.
4. What is the difference between a controlled component and an uncontrolled component?
In React, the terms "controlled" and "uncontrolled" components refer to the way data is managed in form elements.
- Controlled Components: Controlled components are components where form data is controlled by React state. Any changes to the input field are handled by functions within the component, which means that the form data is directly controlled by the React component. The value of the input field is always driven by the state in the component. Here's an example:
import React, { useState } from 'react';
function MyForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
}
const handleSubmit = (event) => {
alert('A name was submitted: ' + value);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
export default MyForm;
- Uncontrolled Components: Uncontrolled components are components where form data is handled by the DOM itself rather than React state. Instead of writing an event handler for every state update, you can use a
ref
to get form values from the DOM. The value of the input field is thus controlled by the DOM itself, not by the React component. Here's an example:
import React from 'react';
class MyForm extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
handleSubmit = (event) => {
alert('A name was submitted: ' + this.inputRef.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.inputRef} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default MyForm;
In general, it's recommended to use controlled components because they allow for more predictable code and are more in line with the "React way" of doing things, which is to keep state in the React component's state and render it declaratively. However, uncontrolled components can be useful for some types of inputs, like file uploads, or for integrating with non-React code.
5. How do you test React components?
Testing React components can be done using several libraries and tools. Here are some of the most commonly used ones:
Jest: Jest is a JavaScript testing framework developed by Facebook. It's great for testing JavaScript and React code. It works out of the box with minimal configuration and has features like a complete and easy-to-use API, mocking support, and a powerful matcher library.
React Testing Library: This is a very light-weight solution for testing React components. It provides light utility functions on top of
react-dom
andreact-dom/test-utils
, in a way that encourages better testing practices. Its primary guiding principle is: "The more your tests resemble the way your software is used, the more confidence they can give you."Enzyme: Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output. Enzyme's API is meant to be intuitive and flexible by mimicking jQuery's API for DOM manipulation and traversal.
Here's an example of how you might test a simple React component using Jest and React Testing Library:
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Button from '../Button'; // This is the component to be tested
test('Check button click updates the count', () => {
const { getByText } = render(<Button />);
// Button initially starts with "Times clicked: 0"
expect(getByText('Times clicked: 0')).toBeInTheDocument();
// Simulate a button click
fireEvent.click(getByText('Click me'));
// Expect the button text to have changed after click
expect(getByText('Times clicked: 1')).toBeInTheDocument();
});
In this example, we're rendering the Button
component and then checking that the initial button text is as expected. We then simulate a button click and check that the button text updates as expected.
Remember, testing is a vast topic and the approach you take will depend on many factors such as the complexity of the component, whether it's a class or functional component, whether it uses state or props, etc.
6. What is prop drilling in React?
Prop drilling is a term used in the React community to refer to the process of getting data to parts of the React Component tree. This involves passing props down from a parent component to its child components, and then further down to their children, and so on. This can become particularly problematic when the tree depth increases, as components in between that don't need the data still need to be passed the props to provide it to components deeper in the tree.
This is not an issue with small applications or components, but it can become cumbersome in larger applications. It can lead to code that is hard to maintain and understand. To avoid prop drilling, you can use state management solutions like Redux, MobX or React's built-in Context API. These solutions allow you to manage and access state from any component without having to pass props down through intermediate components.
7. What are Custom Hooks?
Custom Hooks are a feature in React that allow you to create your own hooks to reuse stateful behavior between different components. Custom Hooks are JavaScript functions whose names are prefixed with the word 'use'. A custom Hook is a normal function which can use other Hooks inside of it.
The purpose of custom Hooks is to allow you to use component logic into reusable functions. For example, you might want to use the same data fetching logic in multiple components. With custom Hooks, you can extract this logic into a reusable function.
Here's an example of a custom Hook:
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const data = await response.json();
setData(data);
setLoading(false);
}
fetchData();
}, [url]);
return { data, loading };
}
export default useFetch;
In this example, useFetch
is a custom Hook that fetches data from a URL. It uses the useState
and useEffect
Hooks internally. You can use it in your components like this:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading } = useFetch('https://api.example.com/data');
if (loading) {
return 'Loading...';
}
return <div>Data: {data}</div>;
}
In this component, we're using the useFetch
custom Hook to fetch data from an API. The useFetch
Hook returns an object with data
and loading
properties, which we can use in our component to render different content based on whether the data is still loading.
8. Explain Strict Mode in React.
StrictMode is a tool for highlighting potential problems in an application. It does not render any visible UI. It activates additional checks and warnings for its descendants.
StrictMode currently helps with:
- Identifying components with unsafe lifecycles
- Warning about legacy string ref API usage
- Warning about deprecated findDOMNode usage
- Detecting unexpected side effects
- Detecting legacy context API
To use the StrictMode
, you just need to wrap your component with it. Here is an example:
import React from 'react';
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode>
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
<Footer />
</div>
);
}
In the above example, the StrictMode
checks will apply to ComponentOne
and ComponentTwo
components but not Header
and Footer
components.
Please note that StrictMode
checks are only run in development mode; they do not impact the production build.
9. How to prevent re-renders in React?
There are several ways to prevent unnecessary re-renders in React:
-
ShouldComponentUpdate: This lifecycle method can be used in class components. It allows you to control whether a component should re-render or not by returning a boolean value. If
shouldComponentUpdate
returnsfalse
, then the component will not re-render.
shouldComponentUpdate(nextProps, nextState) {
// compare with current props and state
return nextProps.id !== this.props.id;
}
-
React.PureComponent:
PureComponent
is similar toComponent
, but it handles theshouldComponentUpdate
method for you. When props or state changes,PureComponent
will do a shallow comparison on both props and state. If nothing has changed, it will not trigger a re-render.
class MyComponent extends React.PureComponent {
// your component code
}
-
React.memo:
React.memo
is a higher order component. It's similar toReact.PureComponent
but for function components instead of classes.React.memo
will do a shallow comparison of props and prevent re-render if props haven't changed.
const MyComponent = React.memo(function MyComponent(props) {
// your component code
});
-
useMemo Hook: The
useMemo
hook allows you to prevent expensive calculations on every render. It returns a memoized version of the function that only re-computes the result when one of the dependencies has changed.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
-
useCallback Hook: The
useCallback
hook returns a memoized version of the callback function that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Remember, preventing re-renders can optimize your app, but it also adds complexity. So, use these techniques wisely and only when necessary.
10. How to re-render the view when the browser is resized?
In React, you can use the window
object's resize
event to trigger a re-render when the browser is resized. However, directly manipulating the DOM or using events like this is not the React way of doing things. Instead, you can use the useState
and useEffect
hooks to create a custom hook that listens for resize events. Here's an example:
import React, { useState, useEffect } from 'react';
// Custom hook
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
// Remove event listener on cleanup
return () => window.removeEventListener('resize', handleResize);
}, []); // Empty array ensures that effect is only run on mount and unmount
return windowSize;
}
function ExampleComponent() {
const size = useWindowSize();
return (
<div>
{size.width}px / {size.height}px
</div>
);
}
In this example, useWindowSize
is a custom hook that listens for the resize
event on the window
object. When the window is resized, it updates the state, which causes a re-render of any component using this hook. The ExampleComponent
uses this hook and will re-render whenever the window size changes.
If you like this blog, you can visit my personal blog sehgaltech for more content.
Posted on March 15, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.