React concepts to help in day to day programming as well as preparing for interviews
React, an open-source JavaScript library, has emerged as one of the most popular choices for building modern web applications. Its robustness, scalability, and declarative approach have revolutionised the way developers construct user interfaces. However, delving into React’s world can be overwhelming, especially for newcomers to the framework. This comprehensive list of questions aims to demystify React’s concepts and provide a solid foundation for developers to harness its full potential.
In this article, I have compiled a diverse range of React interview questions that cover various topics, from the fundamental concepts of React components, state, and props, to more advanced topics like hooks, context API, and performance optimisation techniques. Whether you are preparing for a junior-level position or a senior developer role, I’ve got you covered. Our questions are designed to not only test your knowledge of React but also to deepen your understanding of the library’s inner workings and best practices. So, let’s dive in and equip yourself with the necessary knowledge and confidence to excel in your React interviews!
Q: Explain the concept of “lifting state up” in React.
Lifting state up refers to moving the state from a child component to its parent component. This is done when multiple components need to share the same state or when state changes should affect multiple components.
import React, { useState } from 'react';
const ParentComponent = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<ChildComponent count={count} increment={increment} />
</div>
);
};
const ChildComponent = ({ count, increment }) => {
return (
<div>
<button onClick={increment}>Increment</button>
<p>Child Count: {count}</p>
</div>
);
};
Q: How does React handle performance optimisation, and what are some techniques to improve performance?
React uses Virtual DOM to efficiently update the actual DOM. Performance optimisations include using shouldComponentUpdate, React.memo, and useCallback to avoid unnecessary renders.
import React, { useState, memo } from 'react';
// Regular functional component
const Item = ({ item }) => {
console.log('Item rendered:', item);
return <li>{item}</li>;
};
// Optimized functional component using React.memo
const MemoizedItem = memo(Item);
const App = () => {
const [items, setItems] = useState(['Apple', 'Banana', 'Orange']);
const addItem = () => {
const newItem = prompt('Enter a new item:');
setItems([...items, newItem]);
};
return (
<div>
<button onClick={addItem}>Add Item</button>
<ul>
{items.map((item, index) => (
<MemoizedItem key={index} item={item} />
))}
</ul>
</div>
);
};
Q: How do you handle state management in large React applications?
For large-scale React applications, you might use state management libraries like Redux or MobX to centralize and manage application state in a predictable manner.
// Example using mobx
import { observable, action, makeObservable } from 'mobx';
class CounterStore {
count = 0;
constructor() {
// To make the state observable and actions (methods) observable
makeObservable(this, {
count: observable,
increment: action,
decrement: action,
});
}
increment() {
this.count += 1;
}
decrement() {
this.count -= 1;
}
}
const counterStore = new CounterStore();
export default counterStore;
Q: What are React render props, and when would you use them?
Render props is a design pattern where a component’s prop is a function that returns React elements. It’s useful when you want to share behaviour between components without using higher-order components or hooks.
// RenderPropsComponent.js
import React from 'react';
const RenderPropsComponent = ({ render }) => {
const data = 'Hello, from RenderPropsComponent!';
return (
<div>
<h2>Render Props Example</h2>
{render(data)}
</div>
);
};
export default RenderPropsComponent;
// App.js
import React from 'react';
import RenderPropsComponent from './RenderPropsComponent';
const App = () => {
const renderData = (data) => {
return <p>{data}</p>;
};
return (
<div>
<h1>React Render Props Example</h1>
<RenderPropsComponent render={renderData} />
</div>
);
};
export default App;
Q: Explain the concept of controlled vs. uncontrolled components in React.
Controlled components have their state managed by React and are typically controlled through props. Uncontrolled components manage their own state, often through refs, and are less reliant on React’s state management.
// Controlled component
import React, { useState } from 'react';
const ControlledInput = () => {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<div>
<h2>Controlled Input Example</h2>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Value: {inputValue}</p>
</div>
);
};
export default ControlledInput;
// Uncontrolled component
import React, { useRef } from 'react';
const UncontrolledInput = () => {
const inputRef = useRef(null);
const handleClick = () => {
const value = inputRef.current.value;
console.log('Input Value (uncontrolled):', value);
};
return (
<div>
<h2>Uncontrolled Input Example</h2>
<input type="text" ref={inputRef} />
<button onClick={handleClick}>Get Value</button>
</div>
);
};
export default UncontrolledInput;
Q: How does React handle error boundaries, and how would you implement one?
Error boundaries are React components that catch JavaScript errors during rendering, in lifecycle methods, and during the whole component tree’s rendering process. You can implement them using the componentDidCatch
lifecycle method or using the static getDerivedStateFromError
method.
// Class component example
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
};
}
componentDidCatch(error, errorInfo) {
// You can log the error or do any custom error handling here
console.error('Error caught:', error, errorInfo);
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong. Please try again later.</h2>;
}
return this.props.children;
}
}
class MyComponent extends Component {
render() {
if (this.props.shouldThrowError) {
// Simulating an error by throwing an exception
throw new Error('This is an intentional error for demo purposes.');
}
return <h1>Hello, React Error Boundaries!</h1>;
}
}
const App = () => {
return (
<ErrorBoundary>
<MyComponent shouldThrowError={false} />
</ErrorBoundary>
);
};
export default App;
// Functional component example
import React, { useState } from 'react';
const ErrorBoundary = ({ children }) => {
const [hasError, setHasError] = useState(false);
const static getDerivedStateFromError(error) {
console.error('Error caught:', error);
return { hasError: true };
}
if (hasError) {
return <h2>Something went wrong. Please try again later.</h2>;
}
return children;
};
const MyComponent = ({ shouldThrowError }) => {
if (shouldThrowError) {
throw new Error('This is an intentional error for demo purposes.');
}
return <h1>Hello, React Error Boundaries!</h1>;
};
const App = () => {
return (
<ErrorBoundary>
<MyComponent shouldThrowError={false} />
</ErrorBoundary>
);
};
export default App;
Q: How can you optimise rendering performance when working with lists in React?
To optimise rendering performance with lists, use the key
prop for each list item, use React's memo
or PureComponent
for item rendering, and consider using libraries like react-virtualized
for efficiently rendering large lists.
Provide a unique key prop to each item while rendering a list
import React from 'react';
const MyList = ({ items }) => {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
};
Using react memo
import React from 'react';
const MyComponent = React.memo(({ prop1, prop2 }) => {
console.log('Rendering MyComponent');
return (
<div>
<p>Prop 1: {prop1}</p>
<p>Prop 2: {prop2}</p>
</div>
);
});
useMemo and useCallback
// useMemo and useCallback can be used to memoize the results
// of expensive calculations or functions, avoiding recomputing
// them on every render.
import React, { useMemo, useCallback } from 'react';
const MyComponent = ({ data }) => {
const processedData = useMemo(() => {
// Some expensive data processing logic
console.log('Data processing');
return data.map((item) => item * 2);
}, [data]);
const handleClick = useCallback(() => {
// Handle click using the processedData
console.log('Processed data:', processedData);
}, [processedData]);
return (
<div>
<button onClick={handleClick}>Click Me</button>
</div>
);
};
Q: What are portals in React, and how would you use them?
Portals in React allow you to render children components into a different DOM element, outside the parent component’s DOM hierarchy. They are useful for rendering elements like modals that need to be positioned relative to the root of the DOM.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Portal Example</title>
</head>
<body>
<div id="root"></div>
<!-- The portal target element -->
<div id="portal-root"></div>
</body>
</html>
// Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
const Modal = ({ isOpen, onClose, children }) => {
if (!isOpen) return null;
return ReactDOM.createPortal(
<div className="modal-overlay">
<div className="modal">
<button className="close-btn" onClick={onClose}>
Close
</button>
{children}
</div>
</div>,
document.getElementById('portal-root')
);
};
export default Modal;
// App.js
import React, { useState } from 'react';
import Modal from './Modal';
const App = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const handleOpenModal = () => {
setIsModalOpen(true);
};
const handleCloseModal = () => {
setIsModalOpen(false);
};
return (
<div>
<h1>React Portal Example</h1>
<button onClick={handleOpenModal}>Open Modal</button>
<Modal isOpen={isModalOpen} onClose={handleCloseModal}>
<h2>Hello from the Modal!</h2>
<p>This content is rendered using a portal.</p>
</Modal>
</div>
);
};
export default App;
Q: How do you handle side effects in React, and what are some common use cases?
Side effects can be managed using the useEffect
hook. Common use cases include data fetching, subscriptions, or manually interacting with the DOM.
import React, { useState, useEffect } from 'react';
const SideEffectExample = () => {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Simulating data fetching using a setTimeout
const fetchData = () => {
setTimeout(() => {
const fakeData = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
setData(fakeData);
setIsLoading(false);
}, 1500);
};
fetchData();
// Cleanup function (equivalent to componentWillUnmount)
return () => {
console.log('Component will unmount');
// Perform any cleanup, e.g., clear intervals, cancel subscriptions, etc.
};
}, []); // Empty dependency array ensures the effect runs only once (on mount)
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Side Effect Example</h1>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
export default SideEffectExample;
Q: What are React hooks, and how do they differ from class components?
React hooks are functions that allow you to use state and other React features in functional components. They were introduced in React 16.8. Class components use lifecycle methods and manage state differently compared to functional components with hooks.
// Functional Component using React Hooks
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
// Class Component
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
increment = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
const { count } = this.state;
return (
<div>
<p>Count: {count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
Q: Explain how React’s context API works and when it’s beneficial to use it.
React’s context API allows you to pass data through the component tree without needing to pass props manually at every level. It’s beneficial when data needs to be shared between deeply nested components.
// MyContext.js
import React, { createContext, useState } from 'react';
// Create a context
const MyContext = createContext();
// Create a context provider
const MyContextProvider = ({ children }) => {
const [data, setData] = useState('Default value');
return (
<MyContext.Provider value={{ data, setData }}>
{children}
</MyContext.Provider>
);
};
export { MyContext, MyContextProvider };
// ComponentA.js
import React, { useContext } from 'react';
import { MyContext } from './MyContext';
const ComponentA = () => {
const { data, setData } = useContext(MyContext);
return (
<div>
<h2>Component A</h2>
<p>Data from context: {data}</p>
<button onClick={() => setData('Updated value in Component A')}>
Update Data
</button>
</div>
);
};
export default ComponentA;
// ComponentB.js
import React, { useContext } from 'react';
import { MyContext } from './MyContext';
const ComponentB = () => {
const { data, setData } = useContext(MyContext);
return (
<div>
<h2>Component B</h2>
<p>Data from context: {data}</p>
<button onClick={() => setData('Updated value in Component B')}>
Update Data
</button>
</div>
);
};
export default ComponentB;
// App.js
import React from 'react';
import { MyContextProvider } from './MyContext';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';
const App = () => {
return (
<MyContextProvider>
<div>
<h1>React Context API Example</h1>
<ComponentA />
<ComponentB />
</div>
</MyContextProvider>
);
};
export default App;
Q: What is React Router, and how do you handle routing in a React application?
React Router is a popular library for handling routing in React applications. It provides components like BrowserRouter
and Route
to define different routes and handle navigation between them.
// App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Contact from './Contact';
const App = () => {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
</div>
</Router>
);
};
export default App;
// Home.js
import React from 'react';
const Home = () => {
return <h2>Welcome to the Home page!</h2>;
};
export default Home;
// About.js
import React from 'react';
const About = () => {
return <h2>This is the About page.</h2>;
};
export default About;
// Contact.js
import React from 'react';
const Contact = () => {
return <h2>Contact us at contact@example.com</h2>;
};
export default Contact;
Q: How do you perform server-side rendering (SSR) in React, and what are the benefits?
Server-side rendering can be achieved using libraries like Next.js or React’s built-in ReactDOMServer
. Benefits include improved SEO, faster initial page loads, and better performance for users on slow connections.
Q: How would you handle forms and form validation in React?
Form handling involves managing form state with React’s state or hooks and using event handlers to update state and handle form submission. Form validation can be done using libraries like formik
or manually using conditional checks.
Q: Explain the concept of Higher-Order Components (HOCs) in React and their use cases.
Higher-Order Components are functions that take a component and return a new enhanced component. They are used for code reuse, logic sharing, and cross-cutting concerns.
// withClickCounter.js
import React, { Component } from 'react';
const withClickCounter = (WrappedComponent) => {
class WithClickCounter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
handleIncrement = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return (
<WrappedComponent
count={this.state.count}
handleIncrement={this.handleIncrement}
{...this.props}
/>
);
}
}
return WithClickCounter;
};
export default withClickCounter;
// MyComponent.js
import React from 'react';
const MyComponent = ({ name, count, handleIncrement }) => {
return (
<div>
<h1>Hello, {name}!</h1>
<p>Click count: {count}</p>
<button onClick={handleIncrement}>Increment Count</button>
</div>
);
};
export default MyComponent;
// App.js
import React from 'react';
import MyComponent from './MyComponent';
import withClickCounter from './withClickCounter';
const EnhancedComponent = withClickCounter(MyComponent);
const App = () => {
return <EnhancedComponent name="John" />;
};
export default App;
Q: How do you handle code splitting and lazy loading in a React application?
Code splitting and lazy loading are typically achieved using React’s lazy
and Suspense
components or through dynamic import()
statements with Webpack. This helps reduce the initial bundle size and improve application performance.
Q: What are the differences between shallow rendering and full rendering in React testing?
In React testing, shallow rendering is a technique that allows you to render a component one level deep, without rendering its child components. This helps you focus on testing the specific component you are interested in, without worrying about the behavior of its child components. Shallow rendering is typically achieved using testing libraries like Enzyme. Full rendering, on the other hand, renders the component along with all its children.
Q: How do you integrate third-party libraries or non-React code with React components?
Integrating third-party libraries can be done using React’s lifecycle methods, hooks, or through custom React wrappers. You might also need to work with refs to interact with non-React code.
Q: What are the benefits of using React over other front-end frameworks or libraries?
React’s virtual DOM, component-based architecture, and large community support make it a popular choice for building dynamic and scalable user interfaces.
Q: Explain the React reconciliation process and how it helps with efficient updates.
React reconciliation is the process of comparing the Virtual DOM with the actual DOM and updating only the differences. This helps in minimizing the number of actual DOM manipulations, leading to better performance. It is crucial for building complex applications where frequent changes in state and props occur.
Hope this article provide some helpful information about React programming. All the best.