1.Create a simple counter component using React Hooks (useState). The counter should have buttons to increment, decrement, and reset the count.
import React, { useState } from ‘react’;
function Counter() {
const [count, setCount] = useState(0);
return (
Count: {count}
setCount(count + 1)}>Increment
setCount(count – 1)}>Decrement
setCount(0)}>Reset
);
}
export default Counter;
2.How does code splitting improve performance?
Code splitting is a technique that allows you to split your code into smaller chunks, which can then be loaded on demand. It helps in reducing the initial bundle size, leading to faster page load times. React supports code splitting via React.lazy() and Suspense to dynamically load components.
const LazyComponent = React.lazy(() => import(‘./Component’));
With code splitting, only the necessary parts of the app are loaded when needed, instead of loading the entire app upfront.
3. Describe the React component lifecycle and the difference between functional and class components?
The three lifecycle phases of react components are
Mounting (e.g., constructor, componentDidMount)
Updating (e.g., componentDidUpdate, shouldComponentUpdate)
Unmounting (componentWillUnmount)
These methods allow you to hook into certain stages of a component’s existence. Functional components use hooks like useEffect to achieve similar behavior.
Functional components are simpler and primarily focus on rendering the UI, while class components include state and lifecycle methods. With the introduction of hooks, functional components can now handle state and lifecycle methods, making them more versatile.
4. Create two components: a parent and a child. The parent should pass a function to the child, and when the child calls this function, it should update a state in the parent.
Answer:
import React, { useState } from ‘react’;
function Child({ updateParent }) {
return (
updateParent(‘Message from Child’)}>Send Message
);
}
function Parent() {
const [message, setMessage] = useState(”);
return (
Parent
Message: {message}
);
}
export default Parent;
5.How does React Router work, and how can you achieve dynamic routing?
React Router uses declarative routing to manage navigation. It leverages BrowserRouter, Route, and Switch components to render different components based on the URL. Dynamic routing is achieved by passing route parameters:
6. When should you use componentDidMount vs. useEffect? How are HOCs used?
componentDidMount is used in class components to execute code after the component is mounted. In functional components, the useEffect hook can achieve the same, but it can be used for both component mounting and updating when you provide dependencies.
HOCs are functions that take a component and return a new enhanced component. They are used to add additional behavior to components, such as logging, authentication checks, or conditional rendering.
const withAuth = (Component) => (props) => {
return isAuthenticated ? : ;
};
7.What are the differences between useEffect and useLayoutEffect?
useEffect runs after the DOM has been painted, while useLayoutEffect runs synchronously after all DOM mutations but before the painting. useLayoutEffect is mainly used for performing measurements or DOM manipulations.
8.How do you use the Context API in React?
The Context API is used for passing data down the component tree without needing props. You create a context using React.createContext(), provide a value using Provider, and consume it with useContext().
const UserContext = React.createContext();
9.What are error boundaries in React?
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree and display a fallback UI. You can implement it using componentDidCatch and getDerivedStateFromError methods.
class ErrorBoundary extends React.Component {
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return Something went wrong. ;
}
return this.props.children;
}
}
10.How can you optimize performance in React applications?
A: Performance can be optimized by using techniques like memoization (React.memo), lazy loading, code splitting, avoiding unnecessary re-renders using shouldComponentUpdate or React.PureComponent, and using useCallback and useMemo hooks.
11.How can you manage state globally in a React application?
Manage global state using Context API, or state management libraries like Redux, Recoil, or MobX. These tools help manage shared state across multiple components.
12.How can you conditionally render elements in React?
Conditional rendering can be done using JavaScript’s ternary operators, && (logical AND), or if statements within JSX:
{isLoggedIn ? : }
13. What is memoization, and how does React.memo help?
Memoization is a technique to cache results of expensive operations. React.memo helps optimize performance by preventing unnecessary re-renders when the props remain unchanged.
const MemoizedComponent = React.memo(MyComponent);
14.Create a simple Todo List application. You should be able to add tasks, mark them as completed, and remove tasks. Use useState for managing the list.
import React, { useState } from ‘react’;
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState(”);
const addTodo = () => {
setTodos([…todos, { text: input, completed: false }]);
setInput(”);
};
const toggleTodo = (index) => {
const newTodos = […todos];
newTodos[index].completed = !newTodos[index].completed;
setTodos(newTodos);
};
const deleteTodo = (index) => { setTodos(todos.filter((_, i) => i !== index));
};
return (
);
}
export default TodoApp;
15.How does useState work, and how can you update state based on the previous value?
useState initializes a state value, and you can update it with a setter function. You can update state based on the previous value by passing a function to the setter:
const [count, setCount] = useState(0);
setCount(prevCount => prevCount + 1);
16.Explain how you can replicate componentWillUnmount behavior in a functional component.
In a functional component, you can replicate componentWillUnmount using the useEffect hook by returning a cleanup function, which will run when the component is unmounted:
useEffect(() => {
return () => {
// Cleanup code here
};
}, []);
17.What is the purpose of getDerivedStateFromProps and how does it differ from componentDidUpdate?
getDerivedStateFromProps is a static method introduced in React 16.3 that runs before rendering, allowing the component to update its state based on changes in props. Unlike componentDidUpdate, it doesn’t have access to the component instance, as it is static. It is meant to replace componentWillReceiveProps.
getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.someValue !== prevState.someValue) {
return { someValue: nextProps.someValue };
}
return null;
}
componentDidUpdate runs after the component has been re-rendered, and you can trigger side-effects or data fetching based on prop or state changes.
18.What are the use cases for the React Context API, and how is it different from Redux?
The Context API is used for managing global state, especially when data needs to be passed deeply into a component tree without using props at every level (prop drilling). It’s simpler than Redux and is often used for small to medium-sized apps or specific use cases like theming or localization.
Example:
const UserContext = React.createContext();
const App = () => (
);
const Dashboard = () => {
const user = useContext(UserContext);
return Hello, {user.name}
;
};
Redux, on the other hand, is a more powerful state management library that provides a centralized store, strict unidirectional data flow, and middleware support, making it suitable for complex state logic.
19.What is prop drilling and how can you avoid it?
Prop drilling occurs when you pass data from a top-level component down to deeply nested child components through multiple layers of props, which can become cumbersome and lead to bloated code. You can avoid prop drilling by using:
Example:
const Grandparent = () => ;
const Parent = ({ user }) => ;
const Child = ({ user }) => {user.name}
;
20.What are the different ways to manage state in React?
State can be managed locally using useState or useReducer. For global state management, you can use Context API, third-party libraries like Redux, MobX, or Zustand. Each solution has its own use cases depending on the complexity of state.
21.How does the Virtual DOM improve performance in React?
The Virtual DOM is a lightweight representation of the real DOM. React uses the Virtual DOM to compute changes by diffing the new state of the UI with the previous state and applying only the necessary updates to the real DOM. This reduces the number of direct manipulations of the DOM, which are costly in terms of performance.
22.How does conditional rendering work in React?
Conditional rendering in React works the same way conditions work in JavaScript. You can use if, ternary operators, or && (logical AND) to render different components or JSX elements based on a condition.
23. How do you implement lazy loading of components in React?
Lazy loading in React can be implemented using the React.lazy() function along with Suspense. This allows you to load components only when they are needed, reducing the initial bundle size.
const LazyComponent = React.lazy(() => import(‘./MyComponent’));
24.How can you handle client-side hydration issues with SSR?
Hydration issues occur when the HTML generated on the server doesn’t match what React expects on the client. This can happen due to mismatches in data or state.
Strategies to avoid hydration issues:
Avoid useEffect for critical rendering logic:
Effects only run after the initial render on the client, so any UI differences caused by useEffect can lead to mismatches.
Ensure consistent data on both server and client:
Make sure that any data used for SSR (e.g., fetched from an API) is available on both the server and client.
Use suppressHydrationWarning:
This prop suppresses hydration warnings for specific elements where mismatches are expected but harmless.
25. How do React batch updates to the Virtual DOM, and why is this important for performance?
React batches state updates to the Virtual DOM during the event handling phase to prevent unnecessary re-renders. When multiple state updates occur in the same event loop, React batches them and applies them in a single render pass, instead of re-rendering after each individual update.
Example:
function handleClick() {
setCount(prev => prev + 1);
setValue(prev => prev + 1);
}
Both setCount and setValue will be batched, causing only one re-render, improving performance by minimizing redundant DOM updates.
Batched updates reduce the number of renders, preventing performance degradation in complex UIs or under heavy user interactions.
26.How can you conditionally render elements in React?
Conditional rendering can be done using JavaScript’s ternary operators, && (logical AND), or if statements within JSX:
{isLoggedIn ? : }
27.Explain how you can replicate componentWillUnmount behavior in a functional component.
In a functional component, you can replicate componentWillUnmount using the useEffect hook by returning a cleanup function, which will run when the component is unmounted:
useEffect(() => {
return () => {
// Cleanup code here
};
}, []);
28.How would you optimize the performance of a large list rendering in React?
Optimize large list rendering using the following strategies:
Virtualization:
Tools like react-window or react-virtualized can be used to render only the visible portion of the list instead of rendering all items at once.
Memoization:
Use React.memo to prevent unnecessary re-renders of list items.
Lazy Loading:
Load data in chunks as the user scrolls (infinite scrolling).
PureComponent / shouldComponentUpdate: For class components, implement shouldComponentUpdate or extend PureComponent to avoid unnecessary updates.
29.How does React handle state immutability, and why is it important?
React encourages immutable state updates because immutability helps React identify when a component’s state has changed. If the state or props object is mutated directly, React cannot detect the change, and components may not re-render as expected. By creating a new copy of the state with updates (using Object.assign or the spread operator), React can efficiently compare the previous and next state and decide whether to re-render the component.
The key is to return a new object each time the state changes, ensuring React’s reconciliation algorithm works properly.
30.Implement a search bar that uses debouncing to minimize the number of API calls made. When the user types in the search box, the API should be called after a 500ms delay, but only if no further input is made during that period.
import React, { useState, useEffect } from ‘react’;
function SearchComponent() {
const [query, setQuery] = useState(”);
const [searchTerm, setSearchTerm] = useState(”);
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
setSearchTerm(query); // API call can be triggered here
}, 500);
return () => clearTimeout(delayDebounceFn); // Cleanup on every key press
}, [query]);
return (
);
}
export default SearchComponent;
31.Create a toggle switch component using useState that switches between “ON” and “OFF” states.
Answer:
import React, { useState } from ‘react’;
function ToggleSwitch() {
const [isOn, setIsOn] = useState(false);
return (
setIsOn(!isOn)}>
{isOn ? ‘ON’ : ‘OFF’}
);
}
export default ToggleSwitch;
32.Create a simple accordion component where clicking on a section title toggles the display of its content.
import React, { useState } from ‘react’;
function Accordion() {
const [activeIndex, setActiveIndex] = useState(null);
const toggleIndex = (index) => {
setActiveIndex(activeIndex === index ? null : index); };
return (
{[‘Section 1’, ‘Section 2’, ‘Section 3’].map((section, index) => (
toggleIndex(index)}>{section}
{activeIndex === index &&
This is content for {section}
}
))}
);
}
export default Accordion;
33.Explain the concept of “lifting state up” in React.
“Lifting state up” refers to moving the state to the closest common ancestor of components that need to share it. Instead of maintaining state in multiple components, the shared state is placed higher up in the component tree and passed down as props to child components, ensuring a single source of truth for that state.
34.How does React handle rendering optimizations?
React optimizes rendering by using techniques like:
Reconciliation:
React compares the current Virtual DOM to the previous one and only updates parts of the real DOM that changed.
Memoization:
Hooks like React.memo, useMemo, and useCallback can be used to prevent unnecessary re-renders by memoizing values or functions that don’t change between renders.
Keyed elements:
Assigning unique keys to list elements helps React efficiently update and reorder elements in lists.
35.What is React Fiber, and why was it introduced?
React Fiber is a complete rewrite of React’s reconciliation algorithm introduced in React 16. It enables React to break down rendering work into smaller units and spread them over multiple frames, making it possible to pause and resume rendering. This makes React more efficient when dealing with complex UIs, improving performance by prioritizing updates and ensuring smoother user interactions.
36.Explain the React reconciliation process in depth. How does it optimize updates to the DOM?
Reconciliation is the process React uses to efficiently update the DOM by comparing the new Virtual DOM with the previous one. React’s diffing algorithm breaks down updates into two phases:
Phase 1:
Virtual DOM comparison (diffing) – React compares the new and old Virtual DOM trees, marking nodes that have changed.
Phase 2:
Commit phase – React applies changes to the actual DOM in a batch, ensuring minimal DOM manipulation. React assumes that elements with the same key are the same, allowing it to quickly re-use parts of the DOM.
React uses the following optimizations:
37. What are React Portals, and when should they be used?
React Portals allow rendering a component’s output into a DOM node that exists outside the hierarchy of the parent component. They are useful when you need to render elements, like modals, tooltips, or dropdowns, that visually appear on top of other content but need to live outside the main DOM tree to avoid styling or overflow issues.
Example use cases:
Modals that need to escape the parent’s overflow context.
Tooltips that need to avoid clipping within container boundaries.
38. What is the React concurrent mode? Explain its key features and how it improves performance.
Concurrent Mode (now renamed as React Concurrent Rendering in future versions) allows React to work on multiple tasks at once and render updates in a non-blocking, interruptible way. Instead of rendering everything synchronously, React can prioritize urgent tasks like user input, deferring less critical updates.
Key features:
Time-slicing:
React splits the work into small chunks and pauses rendering when needed, avoiding UI blocking.
Suspense:
Allows React to wait for asynchronous data (like data fetching) before rendering a component.
Priority scheduling:
Updates can be prioritized based on their urgency, improving responsiveness in large apps.
39. What are Render Phases in React 18, and how do they differ from the previous versions?
In React 18, React introduced two phases for rendering:
Render Phase:
React calls your components to create the Virtual DOM tree. This phase can be paused and resumed to prioritize more important tasks.
Commit Phase:
React applies changes to the DOM and executes side-effects (useEffect). This phase is always synchronous.
In React 18, Concurrent Rendering can interrupt the Render Phase to allow for responsive updates and scheduling, ensuring smoother interactions.
40. How would you handle a memory leak in a React component?
Memory leaks in React components are often caused by:
Not cleaning up effects in useEffect (e.g., not removing event listeners or subscriptions).
Components that remain in memory after being unmounted, due to references like timers, event listeners, or subscriptions.
Prevention strategies:
Use cleanup functions in useEffect.
Clear timers, intervals, or subscriptions on component unmount.
Avoid stale references and unnecessary state updates that could prevent garbage collection.
Example cleanup in useEffect:
jsx
Copy code
useEffect(() => {
const interval = setInterval(() => { /* some task */ }, 1000);
return () => clearInterval(interval); // Cleanup
}, []);
41. Explain the difference between controlled and uncontrolled components in React. Which one would you prefer, and why?
Controlled components are components where the form data is handled by the React component state. You manage the form input values using useState or similar hooks, with the input value always tied to the component’s state.
Uncontrolled components manage form data using the DOM itself, with the input value stored directly in the input element. You access the input value via refs when needed.
Preferred approach:
Controlled components are generally preferred because they provide more control over form data and make it easier to handle validation and data flow.
42. What are Suspense boundaries, and how do they help with handling asynchronous code in React?
Suspense boundary allows you to define regions of your component tree that should wait for some asynchronous operation to complete before rendering. Suspense works well with React.lazy for code-splitting or data-fetching with Suspense-enabled libraries.
A Suspense boundary defines where the fallback UI should be displayed while waiting for asynchronous data. This improves UX by only blocking the necessary part of the UI while the rest remains interactive.
Example:
Loading…