React Interview Questions
React Interview Questions
1. What is ReactJS?
ReactJS is a JavaScript library used to build reusable components for the view layer in MVC architecture.
It is highly efficient and uses a virtual DOM to render components. It works on the client side and is
written in JSX.
Virtual DOM: React uses a virtual DOM to efficiently update and render components, ensuring
fast performance by minimizing direct DOM manipulations.
Hooks: React hooks allow functional components to manage state and side effects, making them
powerful and more flexible.
JSX: It stands for JavaScript and XML and allows you to write HTML in React.
Props and State: props are like function parameters and State is similar to variables.
Virtual DOM: It is a lightweight copy of the actual DOM which makes DOM manipulation easier.
Props are used to pass data from one component to another. The state is local data storage that is local
to the component only and cannot be passed to other components.
Props can be used with state and The state can be used only with the state
functional components. components/class component (Before 16.0).
The Virtual DOM in React is an in-memory representation of the actual DOM. It helps React efficiently
update and render the user interface by comparing the current and previous virtual DOM states using a
process called diffing.
Efficient Rendering: The Virtual DOM is an in-memory representation of the actual DOM that
React uses to optimize the process of updating and rendering UI changes.
Diffing Algorithm: React compares the current and previous versions of the Virtual DOM using a
diffing algorithm, identifying the minimal set of changes required to update the real DOM.
Batch Updates: Instead of updating the real DOM immediately, React batches multiple changes
to reduce unnecessary re-renders, improving performance.
Faster Updates: Since updating the real DOM is slow, React minimizes direct DOM manipulations
by only making updates where necessary after comparing the Virtual DOM.
Declarative UI: With the Virtual DOM, React allows developers to write code in a declarative
style, letting React handle when and how to efficiently update the UI.
6. What is JSX?
JSX is basically a syntax extension of regular JavaScript and is used to create React elements. These
elements are then rendered to the React DOM. All the React components are written in JSX. To embed
any JavaScript expression in a piece of code written in JSX we will have to wrap that expression in curly
braces {}.
<h1>
Hello,
{name}.Welcome to GeeksforGeeks.
</h1>
);
A Component is one of the core building blocks of React. In other words, we can say that every
application you will develop in React will be made up of pieces called components. Components make
the task of building UIs much easier.
Functional Components: Functional components are simply javascript functions. We can create
a functional component in React by writing a javascript function.
Class Components: The class components are a little more complex than the functional
components. The functional components are not aware of the other components in your
program whereas the class components can work with each other. We can pass data from one
class component to another class component.
In general, browsers are not capable of reading JSX and only can read pure JavaScript. The web browsers
read JSX with the help of a transpiler. Transpilers are used to convert JSX into JavaScript. The transpiler
used is called Babel
9. Explain the steps to create a react application and print Hello World?
To install React, first, make sure Node is installed on your computer. After installing Node. Open the
terminal and type the following command.
cd <<Application_Name>>
Javascript
import "./App.css";
function App()
return <div className="App">Hello World !</div>;
npm start
To create an event in React, attach an event handler like onClick, onChange, etc., to a JSX element.
Define the handler function to specify the action when the event is triggered, such as updating state or
executing logic.
Javascript
function Component() {
doSomething(e);
e.preventDefault();
Lists are very useful when it comes to developing the UI of any website. Lists are mainly used for
displaying menus on a website, for example, the navbar menu. To create a list in React use the map
method of array as follows.
Javascript
return <li>{number}</li>;})
ReactDOM.render(<ul>{updatedNums}</ul>, document.getElementById("root"));
A “key” is a special string attribute you need to include when creating lists of elements in React. Keys are
used in React to identify which items in the list are changed, updated, or deleted. In other words, we can
say that keys are used to give an identity to the elements in the lists.
Multi-line comment: We can write multi-line comments in React using the asterisk format /* */.
Single line comment: We can write single comments in React using the double forward slash //.
React renders HTML to the web page by using a function called render(). The purpose of the function is
to display the specified HTML code inside the specified HTML element. In the render() method, we can
read props and state and return our JSX code to the root component of our app.
16. What is state in React?
The state is an instance of React Component Class that can be defined as an object of a set of observable
properties that control the behaviour of the component. In other words, the State of a component is an
object that holds some information that may change over the lifetime of the component.
React allows us to pass information to a Component using something called props (which stands for
properties). Props are objects which can be used inside a component
We can access any props inside from the component’s class to which the props is passed. The props can
be accessed as shown below:
this.props.propName;
Higher-order components or HOC is the advanced method of reusing the component functionality logic.
It simply takes the original component and returns the enhanced component. HOC are beneficial as they
are easy to code and read. Also, helps to get rid of copying the same logic in every component.
19. Explain the difference between functional and class component in React?
A functional component is just a plain JavaScript A class component requires you to extend from
pure function that accepts props as an argument React. Component and create a render function
No render method used It must have the render() method returning JSX
React lifecycle methods (for example, React lifecycle methods can be used inside class
componentDidMount) cannot be used in components (for example,
functional components. componentDidMount).
ReactJS uses one-way data binding which can be Component to View or View to Component. It is also
known as one-way data flow, which means the data has one, and only one way to be transferred to other
parts of the application. In essence, this means child components are not able to update the data that is
coming from the parent component. It is easy to debug and less prone to errors.
Here, we cover all intermediate level react interview questions with answers, that recommeded for
freshers as well as for experienced professionals having 1 – 2 years of experience.
Conditional rendering in React involves selectively rendering components based on specified conditions.
By evaluating these conditions, developers can control which components are displayed, allowing for
dynamic and responsive user interfaces in React applications.
Here if the boolean isLoggedIn is false then the DisplayLoggedOut component will be rendered
otherwise DisplayLoggedIn component will be rendered.
React Router is a standard library for routing in React. It enables the navigation among views of various
components in a React Application, allows changing the browser URL, and keeps the UI in sync with the
URL.
npm i react-router-dom
1. Router(usually imported as BrowserRouter): It is the parent component that is used to store all
of the other components. Everything within this will be part of the routing functionality
2. Switch: The switch component is used to render only the first route that matches the location
rather than rendering all matching routes.
3. Route: This component checks the current URL and displays the component associated with that
exact path. All routes are placed within the switch components.
Initialization: This is the stage where the component is constructed with the given Props and
default state. This is done in the constructor of a Component Class.
Mounting: Mounting is the stage of rendering the JSX returned by the render method itself.
Updating: Updating is the stage when the state of a component is updated and the application is
repainted.
Unmounting: As the name suggests Unmounting is the final step of the component lifecycle
where the component is removed from the page.
Mounting is the phase of the component lifecycle when the initialization of the component is completed
and the component is mounted on the DOM and rendered for the first time on the webpage. he
mounting phase consists of two such predefined functions as described below
componentDidMount() Function: This function is invoked right after the component is mounted
on the DOM.
We use the setState() method to change the state object. It ensures that the component has been
updated and calls for re-rendering of the component. The state object of a component may contain
multiple attributes and React allows using setState() function to update only a subset of those attributes
as well as using multiple setState() methods to update each attribute value independently.
Refs are a function provided by React to access the DOM element and the React element that you might
have created on your own. They are used in cases where we want to change the value of a child
component, without making use of props and all. They have wide functionality as we can use callbacks
with them.
Hooks are a new addition in React 16.8. They let developers use state and other React features without
writing a class. Hooks doesn’t violate any existing React concepts. Instead, Hooks provide a direct API to
react concepts such as props, state, context, refs and life-cycle
29. Explain the useState hook in React?
The most used hook in React is the useState() hook. Using this hook we can declare a state variable
inside a function but only one state variable can be declared using a single useState() hook. Whenever
the useState() hook is used, the value of the state variable is changed and the new variable is stored in a
new cell in the stack.
When you use useState(), you declare a state variable and a function to update that state. React then
manages this state internally and triggers a re-render of the component when the state changes. This
allows functional components to maintain and update their internal state over time.
The useEffect hook in React eliminates the side effect of using class based components. It is used as an
alternative to componentDidUpdate() method. The useEffect hook accepts two arguments where second
argument is optional.
useEffect(function, dependency)
The dependency decides when the component will be updated again after rendering.
when we are trying to render more than one root element we have to put the entire content inside the
‘div’ tag which is not loved by many developers. So since React 16.2 version, Fragments were introduced,
and we use them instead of the extraneous ‘div’ tag. The following syntax is used to create fragment in
react.
<React.Fragment>
<h2>Child-1</h2>
<p> Child-2</p>
</React.Fragment>
React Developer Tools is a Chrome DevTools extension for the React JavaScript library. A very useful tool,
if you are working on React.js applications. This extension adds React debugging tools to the Chrome
Developer Tools. It helps you to inspect and edit the React component tree that builds the page, and for
each component, one can check the props, the state, hooks, etc.
CSS modules are a way to locally scope the content of your CSS file. We can create a CSS module file by
naming our CSS file as App.modules.css and then it can be imported inside App.js file using the special
syntax mentioned below.
Syntax:
Styled-component Module allows us to write CSS within JavaScript in a very modular and reusable way in
React. Instead of having one global CSS file for a React project, we can use styled-component for
enhancing the developer experience. It also removes the mapping between components and styles –
using components as a low-level styling construct
npm i styled-components
Javascript
width : 100px ;
cursor: pointer ;
text-decoration : none;
Prop drilling is basically a situation when the same data is being sent at almost every level due to
requirements in the final level. The problem with Prop Drilling is that whenever data from the Parent
component will be needed, it would have to come from each level, Regardless of the fact that it is not
needed there and simply needed in last.
For further reading, check out our dedicated article on Intermediate ReactJS Intermediate Interview
Questions. Inside, you’ll discover over 20 questions with detailed answers.
Here, we cover advanced react interview questions with answers for experienced professionals, who
have over 5+ years of experience.
36. What is custom hooks in React?
Custom hooks are normal JavaScript functions whose names start with “use” and they may call other
hooks. We use custom hooks to maintain the DRY concept that is Don’t Repeat Yourself. It helps us to
write a logic once and use it anywhere in the code.
Eliminating the use of inline attributes as they slow the process of loading
Lazy loading
useRef createRef
It is a hook. It is a function.
It uses the same ref throughout. It creates a new ref every time.
The refs created using the useRef can persist for The refs created using the createRef can be
the entire component lifetime. referenced throughout the component.
React-redux is a state management tool which makes it easier to pass these states from one component
to another irrespective of their position in the component tree and hence prevents the complexity of the
application. As the number of components in our application increases it becomes difficult to pass state
as props to multiple components. To overcome this situation we use react-redux
It provides centralized state management i.e. a single store for whole application
Since it offers persistent state management therefore storing data for long times become easier
There are four fundamental concepts of redux in react which decide how the data will flow through
components
Actions: Actions are simple objects which conventionally have two properties- type and payload
Reducers: Reducers are pure functions that update the state of the application in response to
actions
When working with Redux we sometimes require multiple reducers. In many cases, multiple actions are
needed, resulting in the requirement of multiple reducers. However, this can become problematic when
creating the Redux store. To manage the multiple reducers we have function called combineReducers in
the redux. This basically helps to combine multiple reducers into a single unit and use them.
Syntax:
books: BooksReducer,
activeBook: ActiveBook
});
Context API is used to pass global variables anywhere in the code. It helps when there is a need for
sharing state between a lot of nested components. It is light in weight and easier to use, to create a
context just need to call React.createContext(). It eliminates the need to install other dependencies or
third-party libraries like redux for state management. It has two properties Provider and Consumer.
44. Explain provider and consumer in ContextAPI?
A provider is used to provide context to the whole application whereas a consumer consume the context
provided by nearest provider. In other words The Provider acts as a parent it passes the state to its
children whereas the Consumer uses the state that has been passed.
In ReactJS, Cross-Origin Resource Sharing (CORS) refers to the method that allows you to make requests
to the server deployed at a different domain. As a reference, if the frontend and backend are at two
different domains, we need CORS there.
axios
fetch
Axios, which is a popular library is mainly used to send asynchronous HTTP requests to REST endpoints.
This library is very useful to perform CRUD operations.
This popular library is used to communicate with the backend. Axios supports the Promise API,
native to JS ES6.
Using Axios we make API requests in our application. Once the request is made we get the data
in Return, and then we use this data in our project.
npm i axios
Javascript
setCounter(counter - 1)
return (
<div>
<div>
{counter}
</div>
<div className="buttons">
<button onClick={handleClick1}>
Increment
</button>
<button onClick={handleClick2}>
Decrement
</button>
</div>
</div>
48. Explain why and how to update state of components using callback?
It is advised to use a callback-based approach to update the state using setState because it solves lots of
bugs upfront that may occur in the future.We can use the following syntax to update state using callback
this.setState(st => {
return(
st.stateName1 = state1UpdatedValue,
st.stateName2 = state2UpdatedValue
})
React Material UI is an open-source React component library, offering prebuilt components for creating
React applications. Developed by Google in 2014, it’s compatible with JavaScript frameworks like
Angular.js and Vue.js. Renowned for its quality designs and easy customization, it’s favored by developers
for rapid development.
Flux architecture in Redux is a design pattern used for managing application state in a unidirectional data
flow. In this architecture, actions are dispatched to modify the store, which holds the entire application
state. The store sends the updated state to the view (UI), and the cycle repeats when new actions are
triggered. Redux follows this structure to ensure a predictable and maintainable state management
system for large applications.
React Hooks are a set of functions introduced in React 16.8 that allow developers to use state, lifecycle
methods, and other React features in functional components. They provide a more straightforward and
flexible way to build React applications, replacing the need for class-based components to manage state
and side effects.
React Hooks are designed to “hook into” React’s existing features, enabling functional components to
access functionalities previously only available in class-based components. With Hooks, developers can
manage component state, handle side effects, and perform various other operations directly within
functional components.
The core concept behind React Hooks is that they enable a more declarative and modular approach to
building React applications. Instead of relying on complex class syntax and lifecycle methods, Hooks
allow you to focus on functions and encapsulate behavior in reusable pieces of logic.
Simplified Component Logic: Hooks allow you to organize logic based on features, not lifecycle
methods or class structures. This results in cleaner and more readable code.
Functional Components with State: Before Hooks, functional components were stateless,
requiring class components for state management and lifecycle control. Hooks bridge this gap,
allowing functional components to have state.
Reduced Complexity: Class components often involved complex patterns, like inheritance and
lifecycle method chaining. Hooks simplify the component structure by using functions.
Improved Reusability: Hooks enable developers to create custom Hooks that encapsulate
common logic, promoting code reuse and a more modular approach to React development.
State Management: In class-based components, state is managed through the this.state object,
and updates are performed with this.setState(). In functional components with Hooks, state is
managed with the useState hook, providing a simpler and more declarative way to update state.
Component Structure: Class components require a more rigid structure with class syntax
and render() methods. Functional components with Hooks are more concise, focusing on a
functional approach without class syntax.
Reusability: Custom Hooks enable you to extract common logic into reusable functions. This
approach is more flexible than creating complex inheritance hierarchies or mixins with class
components.
Overall, React Hooks represent a shift towards a more functional and modular approach to React
development, simplifying state management, reducing boilerplate, and enhancing reusability. They have
become the preferred method for building modern React applications, offering a more intuitive and
efficient way to work with React’s core features.
React provides a variety of hooks that allow you to manage state, handle side effects, and implement
other functionalities in functional components. Here are the most commonly used React Hooks:
1. useState
2. useEffect
Handles side effects such as data fetching, subscriptions, and DOM manipulations.
Uses a dependency array to control when the effect runs and whether it requires cleanup.
3. useContext
Helps avoid prop drilling by allowing components to access global or shared state directly.
Commonly used with React’s Context API to manage application-wide states like themes or user
authentication.
4. useReducer
Ideal for scenarios with multiple state transitions or complex state logic.
5. useRef
Useful for accessing DOM elements, managing focus, or storing mutable objects.
6. useCallback
Helps optimize performance by ensuring that functions remain consistent unless dependencies
change.
7. useMemo
Useful for optimizing expensive calculations or derived state that depends on multiple variables.
Uses a dependency array to control when the memoized value should be recalculated.
8. useLayoutEffect
Similar to useEffect, but runs before the component is painted to the screen.
Useful for scenarios where DOM manipulations or layout changes must occur before rendering.
Often used for animations, layout adjustments, or ensuring correct measurements.
9. useImperativeHandle
Allows child components to expose specific methods to parent components via refs.
Useful for creating imperative APIs or controlled components where the parent component
needs to interact with the child in a specific way.
These are the most commonly used React Hooks, each with unique purposes and use cases.
Understanding these hooks provides a solid foundation for building functional React components and
managing state, side effects, and component behavior effectively.
useState is one of the fundamental React Hooks that allows functional components to have stateful
behavior. Before the introduction of React Hooks, state management was limited to class-based
components, where state was managed using this.state and updated with this.setState(). useState brings
this capability to functional components, making them just as versatile as class components.
Definition
useState is a function provided by React that returns a stateful variable and a function to update that
variable. It’s used to manage the component’s internal state, allowing for dynamic and interactive
behavior.
The basic syntax for useState involves calling the hook with an initial state value. It returns an array with
two elements: the current state and a function to update the state.
state: The current state variable. It holds the current value of the state.
setState: A function that updates the state. Calling setState with a new value re-renders the
component with the updated state.
When you call setState, React schedules a re-render for the component. The new state value is used in
the component’s subsequent renders, allowing you to update the component’s behavior or content
based on the updated state.
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
In this example, the count state is initialized to 0. When the button is clicked, the increment function
calls setCount to update the state. This triggers a re-render, updating the displayed count.
Functional Updates
If you need to update state based on the previous state, it’s best to use the functional form of setState.
This approach avoids potential issues with stale state, especially in asynchronous environments.
};
In this example, setCount takes a function that receives the previous state and returns the new state.
This ensures that the update is based on the most recent state.
Managing Component State: useState is used for managing simple state in functional
components, such as form inputs, counters, toggles, or simple arrays and objects.
Conditional Rendering: useState allows you to conditionally render content based on the
current state.
Dynamic Styles and Classes: State changes can be used to update styles, classes, or other
dynamic elements in a component.
In summery useState is a versatile hook that enables functional components to have stateful behavior,
offering a simple and efficient way to manage state in React applications. By understanding its core
concepts, syntax, and best practices, you can leverage useState to create interactive and dynamic React
components.
The useEffect hook is a fundamental React Hook used to manage side effects within functional
components. Side effects are operations that affect something outside the scope of the current function,
such as fetching data, updating the DOM, or subscribing to events. Before Hooks, class-based
components used lifecycle methods to handle side effects,
like componentDidMount, componentDidUpdate, and componentWillUnmount. With useEffect,
functional components can manage side effects in a unified way.
Purpose of useEffect
The primary purpose of useEffect is to handle operations that must occur after the component has
rendered or updated. It can be used for various side effects, including:
Data Fetching: Making network requests to fetch data from APIs or databases.
Event Handling: Subscribing to DOM events or custom events within the application.
Updating External Resources: Modifying browser document properties, like title or focus, or
interacting with third-party libraries.
useEffect takes a function as its first argument, representing the side effect to be executed. It also takes
an optional dependency array as its second argument, which controls when the effect runs. If the
dependency array is empty, the effect runs only once when the component is mounted. If it contains
variables, the effect runs whenever those variables change.
useEffect(() => {
fetch('/api/data')
}, []); // The effect runs only once, when the component is mounted
};
Empty Array ([]): The effect runs once when the component is mounted and does not re-run on
updates. This is equivalent to componentDidMount.
Array with Dependencies: The effect runs on mount and re-runs whenever the specified
dependencies change. This is equivalent to componentDidUpdate.
No Array: The effect runs on every render, potentially leading to performance issues or infinite
loops. This behavior is generally avoided.
Cleanup Functions
Another critical aspect of useEffect is cleanup functions. If the effect sets up something that needs to be
cleaned up (like event listeners or timers), you should return a cleanup function from
the useEffect function. This ensures proper resource management and prevents memory leaks.
useEffect(() => {
console.log('Interval running');
}, 1000);
In summery, useEffect is a powerful hook for managing side effects in functional components. It allows
you to handle operations like data fetching, event handling, and timers in a simple and unified way. The
dependency array plays a crucial role in controlling the behavior of useEffect, ensuring that side effects
run at the right times. Proper use of cleanup functions is essential for avoiding memory leaks and
ensuring smooth component lifecycle management. Understanding these concepts is key to
using useEffect effectively in React applications.
A dependency array is the second argument passed to the useEffect hook in React. It is used to
determine when the effect should run or re-run. This array contains one or more variables that
the useEffect function depends on. The presence and content of the dependency array directly influence
the behavior of useEffect, guiding when and how often the effect should execute.
The dependency array plays a critical role in ensuring the correct execution of side effects and preventing
unintended behavior. Here’s why it’s important:
1. Control Over Effect Execution
The dependency array allows you to specify when the useEffect should run or re-run. This control helps
you manage side effects efficiently and avoid unnecessary re-renders, which can lead to performance
issues or infinite loops.
Empty Array ([]): If the dependency array is empty, the useEffect runs once when the
component is mounted. This behavior is similar to componentDidMount in class-based
components.
Specified Dependencies: If the array contains specific variables, the effect re-runs only when
those variables change. This allows you to manage side effects based on specific conditions,
similar to componentDidUpdate.
When the dependency array is missing, the useEffect function runs on every render. This behavior can
easily lead to infinite loops if the effect itself triggers a state change, causing a re-render and
another useEffect execution. By using a properly constructed dependency array, you can avoid these
infinite loops and ensure stable component behavior.
The dependency array also plays a role in resource management and cleanup. By controlling when the
effect re-runs, you can ensure proper cleanup of resources like event listeners, timers, or network
subscriptions.
Specifying the correct dependencies ensures that the useEffect runs at the right times, based on the
component’s logic and requirements. This precision is crucial for consistent behavior, especially in
complex components where multiple effects might interact.
Consider a component that fetches data from an API based on a given ID. The useEffect should re-run
whenever the id changes to fetch new data.
useEffect(() => {
fetch(`/api/data/${id}`)
};
In this example, the dependency array contains [id], indicating that the effect should re-run whenever
the id prop changes. Without this dependency array, the effect might not run when needed or could lead
to unintended behavior.
In Summery, the dependency array is a key component of the useEffect hook, allowing you to control
when the effect should run or re-run. It plays a crucial role in managing side effects, avoiding infinite
loops, and ensuring efficient resource management. By understanding the importance of dependency
arrays, you can use useEffect effectively and maintain stable, performant React components.
A custom Hook is a function in React that allows you to encapsulate reusable logic for use across multiple
components. Custom Hooks enable you to extract common behaviors, like fetching data, managing form
state, or handling authentication, into a single function, promoting code reusability and modularity. They
follow the same rules as standard React Hooks and can use other Hooks within their implementation.
Custom Hooks help reduce redundancy, maintain cleaner code, and facilitate component-based design.
By sharing logic through custom Hooks, you can create more scalable and maintainable React
applications while adhering to the principles of functional components.
The useContext hook is a React Hook that allows functional components to access values from a React
context without prop drilling. Context in React is used to share data or state across components without
having to pass props through every level of the component tree. The useContext hook provides a simple
and efficient way to consume context values directly.
Purpose of useContext
The primary purpose of useContext is to enable components to access shared state or data without
relying on prop drilling. This is useful when you have a global or shared state that needs to be accessible
across multiple components. It reduces the need to pass props through intermediary components,
simplifying the component structure.
To use useContext, you need a context object created with React.createContext(). The context object
provides a Provider component that defines the context’s value, and a Consumer component for
accessing the context. However, the useContext hook simplifies this by allowing functional components
to access context directly.
// Create a context
<ThemeContext.Provider value="dark">
{children}
</ThemeContext.Provider>
);
};
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
Benefits of useContext
Simplifies Context Consumption: useContext eliminates the need for a Consumer component,
allowing direct access to context within functional components.
Encourages Reusable Logic: Custom Hooks can use useContext to create reusable logic that
relies on context, promoting cleaner and more modular code.
Global State Management: useContext is often used with a context that holds global state, like
user authentication status or theme information.
Component Libraries: Context can provide default values or configurations for component
libraries, allowing components to access shared settings.
Nested Component Trees: When components are deeply nested, useContext provides a way to
share data without passing props through every level.
In summery, the useContext hook is a powerful tool in React for accessing context values within
functional components. It simplifies the consumption of context, reduces prop drilling, and encourages a
more modular and reusable code structure. Understanding useContext is key to building React
applications that efficiently manage shared state and promote clean component architecture.
What is useRef?
useRef is a React Hook that returns a mutable ref object. This ref object can hold a mutable value that
persists across renders without triggering a re-render. Unlike state, changing the value of a ref does not
cause the component to re-render. useRef is primarily used for accessing and storing references to DOM
elements, but it can also be used to store any mutable value that needs to persist across renders.
1. Accessing DOM Elements: One of the primary use cases for useRef is accessing DOM elements
directly. By creating a ref and attaching it to a DOM element, you can interact with the DOM
imperatively.
useEffect(() => {
};
2. Storing Previous Values: useRef can be used to store previous values of state or props without
triggering re-renders. This is useful for comparing previous and current values in useEffect or
other lifecycle methods.
useEffect(() => {
prevValueRef.current = value;
});
};
3. Storing Mutable Values: useRef can store any mutable value that needs to persist across
renders, such as timers, intervals, or flags.
useEffect(() => {
console.log('Timer tick');
}, 1000);
return () => {
clearInterval(timerIdRef.current);
};
}, []);
};
4. Optimizing Performance: useRef can be used to store values that do not trigger re-renders but
are used in computations or calculations.
useEffect(() => {
processedDataRef.current = processData(data);
}, [data]);
};
useRef provides a versatile way to store mutable values that persist across renders and is particularly
useful for accessing and manipulating the DOM imperatively. Understanding its use cases and limitations
can help you leverage it effectively in your React applications.
useMemo and useCallback are two React Hooks designed to optimize React components’ performance
by memoizing values and functions. Although they serve similar purposes, their primary focus and use
cases differ.
useMemo
Purpose: useMemo is used to memoize computed values or derived data to avoid unnecessary
recalculations on re-renders. This is useful when a complex or computationally expensive
operation depends on one or more dependencies.
Behavior: It returns a memoized value that is recomputed only when the dependencies change.
The dependency array controls when the memoization should update.
Common Use Cases: useMemo is ideal for memoizing derived data, complex calculations,
filtered lists, or objects that require heavy computation.
Example of useMemo:
// Expensive calculation
};
In this example, useMemo is used to memoize the total price of items in a list. The calculation is
recomputed only when the items prop changes.
useCallback
Purpose: useCallback is used to memoize functions to avoid creating new function instances on
each re-render. This is useful when you need to pass a callback to child components or when a
function is expensive to create.
Behavior: It returns a memoized function that is recreated only when its dependencies change.
The dependency array determines when the memoization should be updated.
Common Use Cases: useCallback is useful for passing stable callbacks to child components to
prevent unnecessary re-renders or for memoizing functions with expensive setups.
Example of useCallback:
console.log("Button clicked");
};
);
In this example, useCallback is used to memoize the handleClick function, ensuring that it doesn’t
change on every re-render. This can help avoid unnecessary re-renders in child components that depend
on stable callbacks.
Key Differences
Use Cases: useMemo is used for optimizing expensive computations, while useCallback is used
to maintain stable function references for callbacks or event handlers.
In summery, while useMemo and useCallback share similarities in memoization, their primary focus and
use cases differ. Understanding when to use each hook can help you optimize your React components’
performance and avoid unnecessary re-renders. Use useMemo for memoizing values and useCallback for
memoizing functions to maintain stability across re-renders and improve application efficiency.
Here is a list of intermediate-level interview questions focused on React Hooks. These questions assess a
candidate’s understanding of core React concepts, as well as their ability to work with React Hooks to
build efficient and scalable applications.
useEffect Basics
What is useEffect, and how does it differ from class component lifecycle methods?
useEffect is a React Hook that manages side effects in functional components, such as data fetching,
subscriptions, and DOM manipulations. It is used to replace class component lifecycle methods
like componentDidMount, componentDidUpdate, and componentWillUnmount.
useEffect takes a function to execute and a dependency array to control when the effect should run or
re-run. It can also return a cleanup function for resource management. The main difference from class
lifecycle methods is that useEffect consolidates multiple lifecycle functionalities into a single hook,
providing a more unified and flexible way to handle side effects in functional components.
Cleanup functions in useEffect are used to manage resources and prevent memory leaks in React
components. When useEffect sets up side effects like event listeners, subscriptions, or timers, it’s
essential to clean them up when the component is unmounted or when the effect re-runs. Cleanup
functions are returned from the useEffect hook and execute before the next effect or when the
component is removed.
By using cleanup functions, you ensure proper resource management and avoid unintended side effects
or memory leaks. For example, if you set an interval in useEffect, the cleanup function would clear that
interval when appropriate.
How would you manage multiple pieces of state in a functional component using useState?
To manage multiple pieces of state in a functional component with useState, you can use one of two
common approaches: maintaining individual state variables for each piece of state or using a single state
object to manage related states. The choice between these approaches depends on the context and
complexity of the component.
If your component has distinct pieces of state that aren’t inherently connected, using
separate useState calls for each piece of state is straightforward and promotes clarity.
return (
<div>
<input
type="text"
placeholder="Username"
value={username}
/>
<input
type="email"
placeholder="Email"
value={email}
/>
</button>
</div>
);
};
In this example, separate state variables manage the username, email, and login status. This approach
makes it easy to understand each state variable’s role and update them independently.
If your component has related pieces of state, using a single state object with multiple properties is an
option. This approach keeps related state together and allows for updating multiple state properties at
once.
username: '',
email: '',
isLoggedIn: false,
});
setUser((prevUser) => ({
...prevUser,
[field]: value,
}));
};
return (
<div>
<input
type="text"
placeholder="Username"
value={user.username}
/>
<input
type="email"
placeholder="Email"
value={user.email}
/>
<button
onClick={() =>
setUser((prevUser) => ({
...prevUser,
isLoggedIn: !prevUser.isLoggedIn,
}))
>
</button>
</div>
);
};
In this example, a single state object manages multiple related pieces of state.
The handleInputChange function helps update the state object without overwriting existing properties.
This approach is useful when you need to keep related state together or perform operations that affect
multiple state properties at once.
Conclusion
Managing multiple pieces of state in a functional component with useState can be achieved using
individual state variables or a single state object with multiple properties. Each approach has its benefits,
depending on the component’s complexity and the relationships among the state pieces. Understanding
both approaches allows you to choose the best strategy for managing state in your React components.
What are some best practices for updating state in a functional component?
Updating state in a functional component using React Hooks, specifically useState, requires careful
consideration to ensure reliable, efficient, and maintainable code. Here are some best practices for
updating state in a functional component:
When updating state based on the previous state, always use the functional form of setState to avoid
stale state issues. This approach ensures you have the latest state during updates.
React state should be treated as immutable. Never modify state directly; instead, create a new object or
array to reflect changes.
If you have related pieces of state, consider managing them within a single state object. This simplifies
state updates and reduces the number of useState calls.
setUser((prevUser) => ({
...prevUser,
name: 'John',
}));
4. Minimize Re-renders
To avoid excessive re-renders, ensure you use useMemo or useCallback to memoize values and functions
that are reused or passed to child components.
// Some computation
return calculateValue();
}, [dependency]);
Descriptive state variable names make the code more readable and maintainable. This practice helps you
understand the purpose of each state variable and avoids confusion.
If state updates are related to side effects, ensure your useEffect dependency arrays are correct.
Incorrect or missing dependencies can lead to unintended re-renders or infinite loops.
useEffect(() => {
If you’re setting side effects that involve resources like event listeners or timers, ensure you have proper
cleanup logic to avoid memory leaks.
useEffect(() => {
console.log("Timer tick");
}, 1000);
}, []);
In summery, Following these best practices for updating state in functional components helps ensure
your React components remain efficient, maintainable, and free from common issues like stale state,
direct mutations, and excessive re-renders. Proper state management leads to better component
behavior and overall application performance.
Handling complex state transitions with useState in React can be challenging, especially when state
management involves multiple variables or intricate logic. Although useState is versatile, for complex
state transitions, it’s often better to use useReducer, which is designed for more complex state logic.
However, you can still use useState for complex transitions with certain strategies and best practices.
Here’s how you can approach this:
When managing related pieces of state, consider using a single state object to keep them together. This
can simplify complex state transitions and make state management more intuitive.
name: '',
age: 0,
email: '',
});
setUser((prevUser) => ({
...prevUser,
...updates,
}));
};
To ensure you’re working with the most recent state, use functional updates. This is especially important
when the new state depends on the previous state.
};
setIsLoggedIn(true);
setUserRole(role);
};
handleLogin('admin');
Directly mutating state can lead to unexpected behavior and make debugging more difficult. Always
create new objects or arrays when updating state to avoid issues.
};
If your component has complex state transitions that involve multiple state variables or intricate logic,
consider using useReducer instead of useState. useReducer allows you to manage state with a reducer
function, similar to Redux, enabling you to define how state changes in response to actions.
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
default:
return state;
};
};
};
In summery, Handling complex state transitions with useState requires careful management of state
variables, functional updates, and avoiding direct mutations. For even more complex logic, consider
using useReducer, which is designed for managing intricate state transitions. These practices will help
you maintain consistent and efficient state management in your React components.
Describe the benefits of using the Context API with useContext compared to prop drilling.
The Context API in React, coupled with the useContext hook, provides a way to share data or state across
multiple components without relying on prop drilling. Prop drilling refers to the practice of passing props
through multiple levels of components, which can become cumbersome and difficult to maintain in large
or complex applications. Here are the benefits of using the Context API with useContext compared to
prop drilling:
Prop drilling occurs when you pass props through several layers of components, even if those
components don’t need the data themselves. This can lead to a complicated component tree, where
changes in a high-level component require updates to every layer. The Context API eliminates the need
for such deep prop drilling by allowing components to access shared data directly from the context.
Using Context:
<Child />
</UserContext.Provider>
);
return <div>{user.name}</div>;
};
Prop drilling complicates the component structure, making it harder to track where data is coming from
and leading to code that is more challenging to maintain. With the Context API, you can provide data at a
high level and access it from any component, simplifying the structure.
When components depend on prop drilling, changes in the component tree can require updates across
multiple layers, making it hard to scale or refactor the application. The Context API allows components to
remain decoupled, making it easier to add, remove, or rearrange components without affecting the data
flow.
4. Centralized State Management
The Context API allows you to manage global or shared state in one place, reducing redundancy and
making it easier to update state across multiple components. This centralization is especially useful for
managing application-wide data like user authentication, themes, or global settings.
The Context API, combined with useContext, encourages the creation of reusable custom hooks that
encapsulate logic related to the context. This promotes modularity and makes it easier to share logic
across different components.
In Summery, Using the Context API with useContext provides significant benefits compared to prop
drilling. It reduces prop drilling, simplifies the component structure, improves maintainability, centralizes
state management, and encourages reusable custom hooks. By embracing the Context API, you can
create more scalable and maintainable React applications.
How can you provide context to a deep component tree without excessive re-renders?
Providing context to a deep component tree in React without causing excessive re-renders involves
careful management of the Context API and understanding how context affects the component re-
rendering process. Here are some best practices and strategies to minimize re-renders when using
context:
When using the Context API, ensure that the value provided by the context doesn’t change unless it’s
meant to trigger a re-render. Changing the context value at a higher level in the component tree can lead
to re-renders in all consuming components, even if the change is unrelated to them.
const toggleTheme = () => setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
return (
<DeepComponent />
</ThemeContext.Provider>
);
};
In this example, the context value only changes when toggleTheme is called, ensuring the re-renders are
controlled.
If your application has multiple types of global state (e.g., theme, user authentication, cart data),
consider using separate contexts for each concern. This way, changes in one context don’t affect others,
reducing unnecessary re-renders.
<ThemeContext.Provider value="light">
<DeepComponent />
</AuthContext.Provider>
</ThemeContext.Provider>
);
Here, changes to the ThemeContext won’t trigger re-renders in components consuming AuthContext,
and vice versa.
To avoid unnecessary re-renders due to changing context values, consider memoizing the context value
with useMemo. This ensures the context value remains stable unless there’s a genuine change.
user,
updateUser: setUser,
return (
<UserContext.Provider value={userContextValue}>
<DeepComponent />
</UserContext.Provider>
);
};
Here, userContextValue is memoized, preventing unnecessary re-renders if the user data doesn’t change.
Ensure that you only use useContext at the necessary levels in the component tree. Consuming context
in components that don’t need it can lead to unnecessary re-renders when the context changes.
By following these best practices, you can provide context to a deep component tree without causing
excessive re-renders. This involves using a consistent context provider, separating contexts for different
concerns, memoizing context values, and consuming context at appropriate levels. By implementing
these strategies, you can improve the efficiency and scalability of your React applications when using the
Context API.
What are common use cases for using useContext in a React application?
The useContext hook in React is a powerful tool that allows functional components to access data from a
React context without prop drilling. This makes it ideal for sharing state across multiple components,
simplifying data management, and reducing code complexity. Here are some common use cases
for useContext in a React application:
The most common use case for useContext is managing global state across an application. Instead of
passing props through many levels (prop drilling), components can access shared state directly from a
context.
Example: A global context for user authentication status, allowing components to know if a user
is logged in without passing props through each level of the component tree.
2. Theme Management
useContext is often used to manage themes or styling across an application. By providing a theme
context, components can switch themes or adjust styling based on a global setting.
Example: A context for light/dark mode, allowing components to switch between themes easily.
Components can access the current theme from context and apply appropriate styles.
Example: A context for managing the current language and providing translation functions,
allowing components to display text in the correct language.
Applications often have global configurations or settings that need to be accessed by multiple
components. useContext is a great way to share these settings across the application.
Example: A context for application configurations, like API endpoints or feature toggles, allowing
components to retrieve and use these settings without prop drilling.
useContext is commonly used for authentication and authorization in React applications. A context can
hold the current user’s information and permissions, enabling components to check access rights or
display user-specific data.
Example: A context for user authentication, providing information about the logged-in user and
their roles. Components can use this context to determine what to render based on the user’s
permissions.
When components need to communicate or coordinate actions across the application, useContext can
provide a shared communication channel.
useContext can be used to integrate state management libraries like Redux or MobX into functional
components. This allows components to consume global state or dispatch actions using context.
Example: A Redux store provided through context, enabling components to dispatch actions and
access global state.
The useContext hook in React provides a flexible way to share state and other data across components
without relying on prop drilling. By using context, you can manage global state, themes, localization,
authentication, configuration, and more, simplifying your component structure and promoting a cleaner,
more maintainable codebase. Understanding these common use cases helps you
apply useContext effectively in your React applications.
What is useReducer?
useReducer is a React Hook that allows you to manage complex state logic in functional components by
using a reducer function, similar to Redux. It is particularly useful when state transitions require complex
logic, multiple state variables, or if you need a consistent pattern for updating state. useReducer provides
an alternative to useState for managing state in more complex scenarios.
useReducer accepts two arguments: a reducer function and an initial state. It returns an array with two
elements: the current state and a dispatch function to send actions to the reducer.
Reducer Function: A function that defines how the state should change based on the given
action. It takes the current state and an action object, and returns a new state.
Dispatch Function: A function to send actions to the reducer, triggering a state transition based
on the logic in the reducer function.
switch (action.type) {
case 'increment':
case 'decrement':
default:
return state;
};
// Initial state for the reducer
return (
<div>
<p>Count: {state.count}</p>
</div>
);
};
In this example, the reducer function handles different actions, updating the state accordingly.
The dispatch function is used to send actions to the reducer, causing a state transition.
While both useReducer and useState are React Hooks for managing state, they are best suited for
different use cases. Here’s a comparison of the two:
useState is ideal for simple state management, where the state transitions are straightforward.
useReducer is designed for more complex state logic, especially when multiple state variables
are involved or when state transitions require more intricate logic.
State Updates:
useState allows you to update state by calling a state update function directly.
useReducer uses a dispatch-action pattern, where you send actions to the reducer to trigger
state transitions.
Maintaining Consistent Logic:
useState is easy to use for simple state management but can become complicated when state
logic grows.
useReducer provides a consistent pattern for handling complex state transitions, similar to
Redux, making it easier to maintain logic across larger applications.
Use useState for simple state management with individual state variables or straightforward
updates.
Use useReducer when managing complex state transitions, handling multiple state variables, or
implementing a consistent state management pattern across a large application.
useReducer is a React Hook designed for managing complex state logic in functional components. It uses
a reducer function and a dispatch-action pattern to handle state transitions, making it an excellent
choice for scenarios where state transitions require more complex logic or consistent patterns. useState,
on the other hand, is best suited for simple state management. Understanding when to use each hook
helps you manage state effectively in your React applications.
A scenario where useReducer is more suitable than useState involves complex state management with
multiple state variables, various actions, or intricate state transitions. Here’s a detailed example
illustrating such a scenario:
In an e-commerce application, the shopping cart might contain multiple items, and you need to manage
complex operations such as adding items, removing items, updating quantities, and calculating totals.
Using useState for each action would require separate state variables and complex update logic,
potentially leading to inconsistency or redundant re-renders.
By using useReducer, you can define a single reducer function that manages the shopping cart’s state
transitions based on the action type. This approach provides a clear pattern for updating state, allowing
you to centralize logic and maintain a consistent structure.
Here’s a breakdown of why useReducer is more suitable for a shopping cart scenario:
1. Complex State Transitions: A shopping cart has various state transitions depending on the user’s
actions. With useReducer, you can manage these transitions in a centralized reducer function,
ensuring consistent logic.
2. Multiple State Variables: The shopping cart state might include a list of items, total quantity, and
total price. Managing these with useState could lead to complex and error-prone logic.
3. Consistent State Management: useReducer uses a dispatch-action pattern, allowing you to
define specific actions to update the state. This approach is more maintainable and scalable as
the application grows.
const initialState = {
items: [],
totalQuantity: 0,
totalPrice: 0,
};
switch (action.type) {
case 'addItem':
if (existingItem) {
: item
);
return {
...state,
items: updatedItems,
totalQuantity: state.totalQuantity + 1,
};
} else {
return {
...state,
totalQuantity: state.totalQuantity + 1,
};
case 'removeItem':
return {
...state,
items: remainingItems,
};
default:
return state;
}
};
};
};
return (
<div>
<h2>Shopping Cart</h2>
<ul>
{state.items.map((item) => (
<li key={item.id}>
</li>
))}
</ul>
</div>
);
};
In this shopping cart scenario, useReducer is more suitable than useState due to the complex state
transitions, multiple state variables, and various actions required to manage the shopping cart’s state.
Using useReducer allows you to define a consistent pattern for state management, ensuring that
complex logic is centralized and easy to maintain. This approach is ideal for applications with intricate
state logic or when you need a scalable solution as the application grows.
How can you manage side effects in a component that uses useReducer?
In React, side effects refer to operations that affect things outside the component’s scope, such as
fetching data, subscribing to events, or modifying the DOM. While useReducer is primarily for managing
complex state transitions, side effects are typically handled with the useEffect hook. In a component that
uses useReducer, managing side effects involves combining useEffect with the reducer pattern, ensuring
that side effects are properly synchronized with state changes.
Here are some strategies for managing side effects in a component that uses useReducer:
useEffect allows you to perform side effects in response to state changes in useReducer. By
placing useEffect in a component with useReducer, you can control when and how side effects occur
based on the reducer’s state transitions.
Example:
switch (action.type) {
case 'FETCH_INIT':
case 'FETCH_SUCCESS':
case 'FETCH_FAILURE':
return state;
};
useEffect(() => {
try {
} catch (error) {
};
fetchData();
return (
<div>
</div>
);
};
In this example, useEffect handles the side effect of fetching data from an API. It dispatches actions to
the useReducer reducer to manage the state transitions for loading, success, and failure. The
dependency array ensures that the side effect runs only when the apiEndpoint changes.
If side effects involve resources that need cleanup (e.g., event listeners, timers, or subscriptions), ensure
that useEffect returns a cleanup function to avoid memory leaks or unintended behavior.
Example:
useEffect(() => {
dispatch({ type: 'INCREMENT' }); // An action that affects the reducer state
}, 1000);
return () => clearInterval(interval); // Cleanup when the component is unmounted or the effect re-runs
}, []);
This example shows how to handle cleanup for side effects, ensuring that resources are released when
the component is unmounted or when the effect re-runs.
In a component using useReducer, managing side effects involves leveraging useEffect to perform
operations like fetching data or setting timers, with proper synchronization based on the reducer’s state
transitions. Returning a cleanup function in useEffect is crucial to manage resources effectively and avoid
memory leaks. By following these strategies, you can ensure side effects are handled efficiently while
maintaining consistent state management with useReducer.
What Is Memoization?
Memoization is an optimization technique used to speed up computer programs by storing the results of
expensive function calls and reusing them when the same inputs occur. In React applications,
memoization involves caching computed values, functions, or components to avoid redundant
computations and re-renders, improving performance and efficiency.
Memoization is achieved in React through specific hooks and components:
useMemo: A React Hook that memoizes the result of a computation based on its dependencies.
It ensures that a value is recalculated only when its dependencies change.
useCallback: A React Hook that memoizes a function, ensuring that it doesn’t change on every
re-render unless its dependencies change.
1. Improves Performance
Memoization reduces unnecessary computations, leading to faster component rendering and overall
application performance. By avoiding redundant calculations, React applications can respond more
quickly to user interactions and data changes.
Example: When rendering a list with complex filtering or sorting, using useMemo can improve
performance by caching the filtered/sorted results, avoiding redundant operations on every re-
render.
In React, re-renders can be costly, especially when components have complex rendering logic.
Memoization ensures that components re-render only when necessary, based on changes to
dependencies or props.
Example: By using React.memo, you can memoize a component, causing it to re-render only
when its props change. This helps reduce unnecessary re-renders in parent components.
Memoization of functions with useCallback ensures that functions don’t change across re-renders unless
their dependencies change. This is crucial when passing callbacks to child components, as changing
function references can trigger unnecessary re-renders.
Memoization can be used to optimize state computations in complex React applications. By caching
derived state with useMemo, you can avoid costly recomputations and improve state management
efficiency.
Example: In a component that derives state from a large dataset, using useMemo can cache the
derived state, ensuring that it’s recomputed only when necessary.
Conclusion
useMemo is a React Hook that memoizes a computed value, ensuring that it is recalculated only when its
dependencies change. This approach can improve performance in React components by reducing
redundant computations, thus decreasing the overall workload during re-renders.
useMemo allows you to cache the result of an expensive computation. This means that the computation
is only performed when its dependencies change, reducing unnecessary recalculations during re-
renders.
Example:
};
In this example, useMemo ensures that the totalPrice calculation is only performed when the items array
changes, avoiding redundant recalculations during other re-renders.
By caching computed values, useMemo can reduce the computational workload during component re-
renders. This is particularly important in scenarios where components re-render frequently, such as
when managing state changes or responding to user interactions.
Example:
import React, { useMemo } from 'react';
return (
<ul>
{filteredItems.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
};
In this example, the filteredItems list is memoized, ensuring that the filter operation is only recomputed
when the items array or searchTerm changes. This reduces unnecessary re-renders when other
component changes occur.
When used in conjunction with other hooks or components, useMemo can ensure that dependencies
remain stable unless specific conditions change. This helps avoid triggering re-renders due to changing
dependencies.
Example:
return { key: 'value' }; // Only create this object once unless dependencies change
};
In this example, useMemo ensures that the memoizedData object is stable, preventing unnecessary re-
renders when passed to child components. This stability is crucial when passing props or callbacks that
should remain unchanged across re-renders.
Conclusion
useMemo and useCallback are both React Hooks used to optimize component performance through
memoization. However, they serve different purposes and are used in distinct scenarios. Here’s a
breakdown of their differences:
useMemo
Purpose: useMemo is used to memoize a computed value, ensuring it is only recalculated when
its dependencies change. This helps avoid unnecessary recomputations, improving performance
in React components with expensive calculations.
Usage: It is typically used when you have a complex or resource-intensive computation that
should be cached and reused during re-renders.
Dependencies: It accepts a dependency array, and the computed value is recalculated only when
one or more dependencies change.
Example:
product.name.toLowerCase().includes(searchTerm.toLowerCase())
);
<ul>
{filteredProducts.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
};
In this example, useMemo is used to memoize the filtered list of products, ensuring it is recalculated only
when the products array or searchTerm changes.
useCallback
Purpose: useCallback is used to memoize a function, ensuring that it doesn’t change across re-
renders unless its dependencies change. This is useful when passing callbacks to child
components to avoid triggering unnecessary re-renders.
Usage: It is typically used when you need to pass a stable function reference to child
components or to maintain the same function instance across re-renders.
Dependencies: It also accepts a dependency array, and the memoized function is recreated only
when the dependencies change.
Example:
console.log("Button clicked");
};
);
In this example, useCallback is used to ensure that the handleClick function remains stable across re-
renders. This stability helps avoid re-rendering the ChildComponent due to changing function references.
Summary of Differences
Function vs. Value: useMemo is for memoizing computed values, while useCallback is for
memoizing functions.
Common Scenarios: useMemo is used when you have an expensive computation to cache,
while useCallback is used when you need a stable function reference.
Understanding the differences between useMemo and useCallback is crucial for using them effectively in
React applications. While both help improve performance, they address different aspects of
memoization and are used in different scenarios.
Provide an example of when you would use useCallback to optimize a React component.
useCallback is a React Hook that memoizes a function, ensuring that it doesn’t change across re-renders
unless its dependencies change. This is particularly useful when passing functions to child components,
as changing function references can trigger unnecessary re-renders.
Here’s an example scenario where useCallback is used to optimize a React component by reducing
unnecessary re-renders:
Consider a parent component that renders a list of child components. Each child component receives a
callback function from the parent, like an event handler for a button. Without useCallback, the callback
function reference might change on every re-render of the parent, causing all child components to re-
render, even if the actual behavior hasn’t changed.
By using useCallback, you can ensure that the function reference remains stable unless the
dependencies change, reducing unnecessary re-renders in child components.
Example
return (
<div>
<span>{item.name}</span>
</div>
);
};
]);
(itemId) => {
},
);
return (
<div>
{items.map((item) => (
))}
</div>
);
};
Explanation
In this example, the ItemList component renders a list of ListItem components, each receiving
a handleDelete callback from the parent. Without useCallback, if the parent re-renders,
the handleDelete function reference could change, causing all child components to re-render, even
though the actual logic of the callback hasn’t changed.
By using useCallback, the handleDelete function is memoized, ensuring it doesn’t change unless its
dependency (setItems) changes. This reduces unnecessary re-renders in child components, leading to
better performance and more efficient component updates. This optimization is especially beneficial in
large component trees where re-renders can impact overall application performance.
What is useRef?
useRef is a React Hook that creates a mutable reference object, allowing you to maintain a value across
re-renders without causing the component to re-render when the reference changes. It can be used to
access DOM elements directly, store mutable values that persist between renders, or create a reference
to a component’s instance for imperative operations.
Here are the common use cases for useRef and how it can be applied in functional components:
One of the primary uses of useRef is to get direct access to DOM elements. By attaching a ref to a DOM
element, you can interact with it imperatively, allowing you to focus elements, scroll to specific sections,
or manipulate DOM properties.
inputRef.current.focus();
}, []);
};
In this example, useRef is used to get a reference to an input element, allowing the component to focus
the input when it mounts.
useRef can store mutable values that need to persist across renders without causing re-renders. This is
useful when you need a value to stay consistent across renders, such as a timer ID or an instance
variable.
useEffect(() => {
console.log('Interval running');
}, 1000);
return () => {
};
}, []);
return <div>Timer is running...</div>;
};
In this example, useRef is used to store a timer ID, allowing the component to manage the timer without
re-rendering. The cleanup function ensures the timer is cleared when the component is unmounted.
useRef can be used with useImperativeHandle to create imperative handles in functional components,
allowing parent components to interact with child components in an imperative manner.
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
});
};
return (
<div>
</div>
);
};
In this example, useImperativeHandle and useRef are used to create an imperative handle for
the ChildComponent, allowing the ParentComponent to interact with it by calling its focus method.
Conclusion
useRef is a versatile React Hook that allows you to create mutable references in functional components.
It can be used to access DOM elements, store mutable values, and create imperative handles for child
components. By understanding its use cases and best practices, you can leverage useRef to implement
powerful and flexible functionalities in your React applications.
Describe a use case where you might use useRef to access a DOM element.
useRef is a React Hook that allows you to create a mutable reference to a DOM element, which can be
used for various tasks such as manipulating the DOM, managing focus, or measuring element size or
position. Here’s a detailed use case where you might use useRef to access a DOM element:
Consider a scenario where you have a form with multiple input fields, and you want to automatically
focus on a specific field when the component is mounted or after a specific action, such as submitting a
form and clearing the inputs. This focus management improves user experience by guiding users through
the form in a predictable way.
useEffect(() => {
// Automatically focus on the email input field when the component is mounted
emailRef.current.focus();
}, []);
e.preventDefault();
// Example: Clear the form and focus on the email field again
setEmail('');
setPassword('');
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email:</label>
<input
type="email"
value={email}
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
/>
</div>
<button type="submit">Submit</button>
</form>
);
};
Explanation
In this example, useRef is used to create references to the email and password input fields.
The emailRef is used to focus on the email input field when the component is mounted, providing an
intuitive starting point for users. Additionally, after the form is submitted and cleared, the focus returns
to the email field, allowing users to quickly start entering new data.
This focus management pattern can improve user experience and accessibility, as it guides users through
the form in a consistent manner. useRef plays a crucial role in this pattern by allowing direct interaction
with DOM elements in functional components, without triggering re-renders when the reference is
accessed or modified.
useImperativeHandle and useRef are both React Hooks that deal with references, but they serve
different purposes and are used in different contexts. Here’s how they differ:
useRef
Purpose: useRef is used to create a mutable reference that persists across component re-
renders. It allows you to directly access DOM elements or store mutable values in a React
component without causing re-renders.
Common Use Cases: Accessing DOM elements, storing mutable values that need to persist
across re-renders, or managing instance-based state.
useEffect(() => {
}, []);
};
In this example, useRef is used to create a reference to an input field, allowing direct interaction with the
DOM to focus the element.
useImperativeHandle
Purpose: useImperativeHandle allows you to customize the instance value exposed to parent
components through ref. It is used to control the exposed API of a child component, enabling
parent components to interact with the child imperatively.
Common Use Cases: Exposing specific methods or properties to parent components, creating
controlled components, or enabling imperative interactions with child components.
useImperativeHandle(ref, () => ({
focus: () => {
},
}));
});
};
return (
<div>
</div>
);
};
export default ParentComponent;
In this example, useImperativeHandle is used to expose a custom focus method to the parent
component, allowing the parent to interact with the child component imperatively.
Key Differences
Purpose:
useRef is primarily used to create a reference to DOM elements or mutable values within a
component.
useImperativeHandle is used to define an API for parent components, allowing them to interact
with child components in an imperative way.
Application:
useRef is often used for direct DOM manipulations or storing instance-based state.
Usage Context:
Understanding the differences between useRef and useImperativeHandle helps you determine which
hook to use based on the specific requirements of your React component or application.
Custom Hooks
What are custom Hooks, and why are they useful in React development?
Custom Hooks are reusable functions in React that encapsulate logic involving other React Hooks or
component behavior. They allow developers to extract common patterns or functionality from
components, promoting code reuse and modular design. Custom Hooks follow the same rules as other
Hooks, such as calling them only at the top level and not within loops, conditions, or nested functions.
Custom Hooks enable you to encapsulate common logic or patterns in a single function, reducing code
duplication across different components. This encapsulation promotes modularity and simplifies
component structure.
Example: A custom Hook that handles data fetching logic, allowing multiple components to fetch
data using the same pattern.
By creating custom Hooks, you can reuse functionality across multiple components without rewriting
code. This promotes consistency and reduces maintenance effort, especially in large-scale React
applications.
Example: A custom Hook for managing form state and validation, reusable across various forms
in an application.
3. Separation of Concerns
Custom Hooks help separate concerns within React components, allowing you to focus on a specific
aspect of a component’s behavior. This separation leads to cleaner code and easier component
management.
Example: A custom Hook that handles user authentication logic, keeping authentication
concerns separate from other component logic.
Custom Hooks can make testing and debugging React components easier. Since custom Hooks
encapsulate logic, you can test them in isolation without testing the entire component. This modularity
leads to better testability and maintainability.
Example: A custom Hook that manages state transitions, allowing you to test state changes
independently from component rendering.
Custom Hooks encourage the use of functional components, reducing the need for class components in
React development. This shift to functional components aligns with modern React best practices and can
lead to a more consistent codebase.
Here’s an example of a custom Hook that manages data fetching, demonstrating how custom Hooks can
encapsulate logic and promote reusability:
useEffect(() => {
setIsLoading(true);
try {
setData(result);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
};
fetchData();
};
if (isLoading) {
return <p>Loading...</p>;
}
if (error) {
};
In this example, the custom Hook useFetch encapsulates the data-fetching logic. It can be reused in
different components by providing the desired url, demonstrating how custom Hooks promote code
reuse and separation of concerns.
Conclusion
Custom Hooks are a powerful feature in React development, allowing developers to encapsulate
reusable logic, improve code reusability, promote functional components, and simplify component
structure. By using custom Hooks, you can create a more modular, maintainable, and scalable React
codebase.
Describe a scenario where you would create a custom Hook to encapsulate shared logic.
A custom Hook in React allows you to encapsulate reusable logic in a single function, promoting code
reusability and modularity. A common scenario where you might create a custom Hook is when you have
a piece of logic that is repeated across multiple components, and you want to centralize it for
maintainability and ease of use.
Imagine you’re building a form-based application where users need to fill out multiple forms with similar
validation requirements. Instead of repeating the form state and validation logic across each component,
you can create a custom Hook to encapsulate this shared logic.
};
e.preventDefault();
setIsSubmitting(true);
};
useEffect(() => {
values,
errors,
handleChange,
handleSubmit,
};
};
if (!values.email) {
} else if (!/\S+@\S+\.\S+/.test(values.email)) {
if (!values.password) {
return errors;
};
const LoginForm = () => {
validate
);
};
return (
<form onSubmit={handleSubmit(submitForm)}>
<div>
<label>Email:</label>
<input
name="email"
type="email"
value={values.email}
onChange={handleChange}
/>
</div>
<div>
<label>Password:</label>
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
/>
</div>
<button type="submit">Submit</button>
</form>
);
};
Explanation
In this example, the custom Hook useForm encapsulates the shared logic for managing form state and
validation. It handles field changes, form submission, and validation checks. The custom Hook is reusable
across different form components, providing a consistent and maintainable pattern for form
management.
The LoginForm component uses the custom Hook to manage the form state and validation,
demonstrating how shared logic can be centralized in a custom Hook, promoting code reuse and cleaner
component structure.
Conclusion
Custom Hooks are a powerful tool for encapsulating shared logic in React applications. By creating a
custom Hook to manage form state and validation, you can avoid code duplication, improve
maintainability, and promote code reusability across multiple components. This approach is beneficial in
scenarios where similar logic is required in different parts of an application.
How do you ensure that custom Hooks adhere to best practices for Hooks usage?
Custom Hooks in React offer a powerful way to encapsulate reusable logic, but it’s crucial to ensure they
adhere to the best practices for Hook usage. Misuse of Hooks can lead to unexpected behavior, errors, or
degraded performance. Here’s how to ensure that custom Hooks are implemented correctly and follow
the best practices for React Hooks:
Hooks have specific rules, and custom Hooks must adhere to them. The primary rules are:
Call Hooks Only at the Top Level: Hooks should not be called inside loops, conditions, or nested
functions. This ensures that React maintains a consistent call order for Hooks.
Call Hooks Only in React Functions: Hooks must be used in React functional components or
other custom Hooks. They cannot be used in class components or non-React functions.
// Correct usage: Hooks are called at the top level of the custom Hook
useEffect(() => {
console.log("Effect runs");
}, []);
};
if (flag) {
};
Custom Hooks should return the values or functions that encapsulate the logic they aim to abstract. This
pattern promotes reusability and consistent use across multiple components.
};
setIsSubmitting(true);
};
return {
values,
errors,
handleChange,
handleSubmit,
};
};
In this example, the custom Hook useForm returns the state values, error messages, and event handlers,
encapsulating form logic in a reusable way.
If custom Hooks use useEffect, ensure that the dependency arrays are specified and accurate. This helps
avoid unintended behavior, such as infinite loops or re-renders.
useEffect(() => {
console.log("Effect running");
return () => {
console.log("Cleanup running");
};
};
State in React should be treated as immutable. Custom Hooks should avoid directly mutating state to
prevent unexpected behavior.
items.push("new item");
};
};
To ensure custom Hooks work as expected, consider testing them independently from components. This
promotes maintainability and allows you to identify potential issues early.
Conclusion
Custom Hooks in React are powerful tools for encapsulating reusable logic, but they must follow the best
practices for Hook usage to ensure consistent behavior and optimal performance. By adhering to the
rules of Hooks, using proper dependency arrays, avoiding direct state mutations, and returning
appropriate values, you can ensure that your custom Hooks are implemented correctly and effectively
support your React development needs.
How can you prevent excessive re-renders when using Hooks in a component?
Excessive re-renders in React components can lead to performance issues and affect user experience. To
prevent this, you need to manage state and Hooks in a way that avoids unnecessary re-renders. Here are
key strategies to help minimize re-renders when using Hooks:
One of the most common causes of excessive re-renders is incorrect or missing dependency arrays
in useEffect. The dependency array determines when the effect should run or re-run. Ensure the array
accurately represents the dependencies.
Correct Usage:
useEffect(() => {
console.log("Effect is running");
useEffect(() => {
useEffect(() => {
// This might cause infinite re-renders if 'someState' is updated within the effect
If you’re passing functions as props to child components, changing function references can trigger re-
renders. Use useCallback to memoize functions, ensuring they remain stable unless dependencies
change.
Example:
console.log("Button clicked");
};
In this example, useCallback ensures the handleClick function remains stable, preventing
the ChildComponent from re-rendering unnecessarily.
useMemo allows you to memoize computed values, avoiding unnecessary recalculations during re-
renders. Use it when you have expensive computations or derived data that should be cached.
Example:
return (
<ul>
{sortedProducts.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
};
If a component should not re-render unless its props change, use React.memo to create a memoized
version of the component. This helps prevent re-renders when props are stable.
Example:
return <div>{value}</div>;
};
useRef allows you to store mutable values without triggering re-renders. If you need to persist values
across re-renders without updating state, useRef is a suitable option.
Example:
console.log("Timer running");
}, 1000);
};
clearInterval(timerIdRef.current);
};
return (
<div>
</div>
);
};
Conclusion
Preventing excessive re-renders in React components involves proper use of Hooks, including correct
dependency arrays, memoization of functions and values, and stable function references. By
using useCallback, useMemo, React.memo, and useRef appropriately, you can minimize unnecessary re-
renders and improve the performance and efficiency of your React applications.
What strategies can you employ to improve the performance of a React application that heavily uses
Hooks?
React applications can suffer from performance bottlenecks when they use Hooks without careful
consideration of state management, rendering, and component structure. To improve performance in a
React application that heavily uses Hooks, you can employ the following strategies:
1. Minimize Re-renders
Reducing unnecessary re-renders is crucial for performance. Here are some strategies to achieve this:
Use React.memo for Pure Components: If a component should only re-render when its props
change, use React.memo to create a memoized version of the component.
Use useCallback for Stable Function References: Memoize functions to prevent re-renders
caused by changing function references, especially when passing callbacks to child components.
console.log("Clicked");
}, []);
};
Use useMemo for Expensive Computations: Memoize computed values to avoid recalculations
during re-renders. This is particularly useful for expensive operations or derived state.
};
Ensure that useEffect has the correct dependency arrays to prevent unnecessary re-renders and infinite
loops.
Example:
useEffect(() => {
console.log("Effect runs");
};
useRef allows you to store mutable values that persist across re-renders without causing re-renders. Use
it to manage DOM references or store instance-based state.
Example:
countRef.current += 1; // No re-render
console.log("Count:", countRef.current);
};
return <button onClick={increment}>Increment</button>;
};
Be cautious about creating state dependencies that cause unnecessary re-renders. This includes:
While the Context API is useful for sharing data across components, it can lead to performance issues if
overused. Avoid excessive context updates and ensure that context values are stable unless necessary.
React automatically batches state updates in event handlers, but in certain cases, you can manually
batch updates to prevent excessive re-renders.
Example:
unstable_batchedUpdates(() => {
setB(2);
});
};
};
Conclusion
Improving the performance of a React application that heavily uses Hooks involves minimizing re-
renders, using memoization, managing dependency arrays, and optimizing context usage. By following
these strategies, you can build efficient, responsive React applications that scale well with increased
complexity and user interactions.
How does React.memo work, and when would you use it with functional components?
React.memo is a higher-order component (HOC) in React that allows you to memoize functional
components, ensuring that they only re-render when their props change. It is a mechanism to optimize
performance by preventing unnecessary re-renders when the component’s props remain the same.
Essentially, React.memo provides a way to implement “pure” components in functional React, akin to
the shouldComponentUpdate lifecycle method in class components.
When you wrap a functional component with React.memo, React compares the component’s props with
its previous props. If the props have not changed, the component will not re-render. This behavior is
particularly useful in large component trees where frequent re-renders can lead to performance issues.
React.memo is beneficial in scenarios where components tend to re-render without a change in props,
leading to redundant rendering and performance degradation. Here are common use cases
for React.memo with functional components:
For components that involve complex rendering logic or expensive computations, using React.memo can
prevent unnecessary re-renders when props haven’t changed, saving resources and time.
Example:
console.log("Rendered");
});
return (
<div>
);
};
In this example, ComplexComponent is memoized with React.memo, ensuring that it only re-renders if
the data prop changes. Clicking the button to increment count will not trigger a re-render
of ComplexComponent because its props remain the same.
If a parent component re-renders frequently, its child components might re-render even if their props
remain unchanged. Using React.memo can prevent these unnecessary re-renders, improving
performance in deeply nested component trees.
When a functional component receives functions or callbacks as props, any change in the function
reference can trigger a re-render. Using React.memo can prevent re-renders if those function references
remain stable.
Example:
));
console.log("Button clicked");
};
export default ParentComponent;
Advanced React Hooks interview questions are designed to assess a candidate’s in-depth understanding
of React Hooks, including how they work, best practices, and advanced concepts. Here are some
advanced interview questions focused on React Hooks:
Question: Explain the difference between useState and useReducer. In what scenarios would you
choose useReducer over useState?
Answer: useState is ideal for simple state management with individual state variables,
while useReducer is useful for complex state logic and managing state transitions with actions.
You’d choose useReducer when dealing with multiple state variables or complex operations, like
updating a shopping cart or handling multiple form fields.
Question: What are dependency arrays in useEffect, and why are they important? How would
you handle an effect that depends on dynamic data?
Answer: Dependency arrays control when the useEffect function runs, based on the variables
listed. If the array is empty, the effect runs once on mount. If it contains variables, the effect re-
runs when those variables change. To handle dynamic data, ensure the dependencies are
correctly listed to avoid unintended re-renders or infinite loops.
3. Performance Optimization
Question: How do useMemo and useCallback help optimize React applications? What are the
risks of overusing them?
4. Custom Hooks
Question: Describe a scenario where you would create a custom Hook. What are the benefits of
custom Hooks in a React application?
Answer: A custom Hook is useful for encapsulating common logic, such as form validation or
data fetching. Custom Hooks promote code reuse and separation of concerns. For example, a
custom Hook for fetching data abstracts the fetching logic, allowing reuse across multiple
components.
Question: What is the role of useContext in React? How can you avoid “prop drilling” using
context?
Answer: useContext allows functional components to consume values from a React context
without passing props through multiple levels (prop drilling). By providing a context at a higher
level in the component tree, you can share state across components without passing props
down through each level.
Question: Explain the differences between useEffect and useLayoutEffect. When would you
use useLayoutEffect instead of useEffect?
Answer: useEffect runs after the component is painted to the screen, while useLayoutEffect runs
before painting, affecting the layout. Use useLayoutEffect when changes must happen before
rendering, such as DOM measurements or critical layout manipulations.
Question: How can useRef be used to manage DOM elements in functional components? Explain
the use of useImperativeHandle in React.
Answer: useRef provides a reference to DOM elements or values that persist across renders,
useful for focus management or accessing DOM attributes. useImperativeHandle allows you to
expose imperative methods to parent components, facilitating controlled components or
specialized behaviors.
Learning Curve Steeper, especially with JSX and extensive ecosystem Easier, simpler synt
Feature React Vue.js
Ecosystem Large, with numerous third-party libraries and tools Smaller, but with a
State Management Requires additional libraries like Redux or Context API Built-in state mana
Flexibility Highly flexible, allows for integration with other libraries or frameworks Flexible, but more
Integration Often integrated with other tools for routing, state management, etc. Comes with built-in
Use Cases Best for complex, large-scale applications Ideal for small to m
Community Support Extensive, with vast resources available Strong, but with fe
React vs Vue js