React is a JavaScript library for building user interfaces, particularly single-page applications (SPAs). It allows developers to create reusable UI components, manage the state efficiently, and handle updates in a predictable way using a virtual DOM.
Advanced React.js interview questions suitable for experienced candidates.
Answer: React uses a reconciliation algorithm to efficiently update the DOM. The algorithm compares the Virtual DOM with the previous version (using a process called “diffing”) and determines the minimal set of changes required to update the actual DOM. React performs this by:
useEffect
hook handle component lifecycle events?Answer: The useEffect
hook in functional components serves as a replacement for many lifecycle methods from class components, such as componentDidMount
, componentDidUpdate
, and componentWillUnmount
. The behavior of useEffect
depends on its dependencies:
componentDidUpdate
behavior).[]
is passed, it behaves like componentDidMount
(it runs once after the first render).[prop]
), it runs whenever any of the dependencies change. It allows handling side effects like data fetching, subscriptions, or manual DOM manipulation in functional components.Answer: Performance optimization in React can be achieved using the following strategies:
React.memo()
to prevent unnecessary re-renders of functional components by memoizing the result based on props.useMemo()
can be used to memoize expensive calculations, and useCallback()
can memoize functions to avoid re-creating them on every render.React.lazy()
and Suspense
for lazy loading components to reduce the initial bundle size.react-window
or react-virtualized
to render only the visible portion of the list.Answer: Higher-order components (HOCs) are functions that take a component as input and return a new component with additional props or behavior. HOCs allow you to reuse component logic without modifying the component itself. A common use case for HOCs is adding additional functionality like authentication checks or logging.
Example:
const withLoading = (Component) => {
return (props) => {
if (props.isLoading) {
return <div>Loading...</div>;
}
return <Component {...props} />;
};
};
const MyComponent = withLoading(MyComponent);
Answer: React Context is a way to share values across the component tree without having to pass props manually at every level. It is ideal for global data like themes, language settings, or user authentication. However, React Context is not well-suited for high-frequency state updates, as it triggers re-renders of all consumers when the value changes, which can affect performance.
When to use Redux:
Answer: Render props is a pattern in React where a component takes a function as a prop and uses it to render content. This function is called a “render prop” and is used to share code between components without using inheritance.
Difference from HOCs:
Example of render props:
class MouseTracker extends React.Component {
render() {
return (
<div>
{this.props.render(this.state)}
</div>
);
}
}
<MouseTracker render={(state) => <p>Mouse position: {state.x}, {state.y}</p>} />
Answer: Code splitting is a technique that allows you to split your application code into smaller chunks that can be loaded on demand, reducing the initial load time. In React, code splitting can be implemented using React.lazy()
and Suspense
to dynamically import components only when needed.
Example of code splitting:
const MyComponent = React.lazy(() => import('./MyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
}
useReducer
and how does it differ from useState
?Answer: useReducer
is a React hook used for managing complex state logic in a component, where state depends on previous states or involves multiple sub-values. It is an alternative to useState
when dealing with complex state transitions, like in forms or when state updates are based on conditions or actions.
Differences:
Example of useReducer
:
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case ‘increment’:
return { count: state.count + 1 };
case ‘decrement’:
return { count: state.count – 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
Answer: Error boundaries are React components that catch JavaScript errors in their child components during rendering, lifecycle methods, and constructors. They prevent the entire application from crashing and allow you to display a fallback UI.
To create an error boundary, you need to implement the componentDidCatch
lifecycle method and render a fallback UI:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log(error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Use it like this:
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
Answer: Concurrent Mode is an experimental feature in React that enables React to interrupt and pause rendering to work on multiple tasks simultaneously. It improves performance by allowing React to prioritize updates, keep the UI responsive, and reduce the time to interactive. It can be enabled using ReactDOM.createRoot()
and works with features like Suspense
to handle async rendering.
Example of enabling Concurrent Mode:
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Answer: The key
prop is a unique identifier given to elements in a list to help React identify which items have changed, been added, or removed. This enables efficient updates and avoids unnecessary re-renders when a list is modified. When key
values are unique and stable, React can perform minimal DOM updates, improving performance.
Answer: Server-Side Rendering (SSR) is the process of rendering a React application on the server rather than in the browser. The server sends a fully rendered HTML page to the client, which improves the initial page load time and enhances SEO (search engine optimization) since search engines can crawl fully rendered content. SSR is typically used in conjunction with frameworks like Next.js.
Answer: Static Site Generation (SSG) is a method where React pages are pre-rendered at build time. This means HTML is generated for each page during the build process and served as static files. Unlike SSR, which generates content on each request, SSG creates faster, static sites that are ideal for content that doesn’t change frequently, offering excellent performance and SEO benefits. React frameworks like Next.js support SSG.
Answer: React’s Context API is a way to pass data through the component tree without having to pass props down manually at every level, making it great for small to medium-sized applications. It’s best suited for sharing global data like themes, authentication states, or language settings.
Redux, on the other hand, is a more powerful state management library that provides a centralized store and allows for more complex state interactions across an entire application. Redux is ideal for larger applications that require a more structured and predictable way of managing state, especially with features like middleware (e.g., Redux Thunk for async actions) and dev tools.
Answer: Pure components are React components that only re-render when their props or state change. React provides the React.PureComponent
class, which automatically implements shouldComponentUpdate()
with a shallow prop and state comparison. By preventing unnecessary re-renders when the component’s inputs (props and state) haven’t changed, pure components can optimize performance, especially in complex UIs with frequent updates.
Answer:
value
and onChange
props for form elements (like input fields). The form elements’ states are synchronized with the component’s state.Suspense
component, and how is it used in conjunction with lazy loading?Answer: Suspense
is a React component that allows for handling asynchronous loading of components or data. When a component is lazy-loaded (e.g., using React.lazy()
), Suspense
can be used to show a fallback UI (like a loading spinner) until the component finishes loading. This improves the user experience by preventing a blank screen and showing a loading state while the component is being fetched.
Answer: Authentication in React can be handled in several ways, depending on the needs of the application:
React Router
to conditionally render components).Answer: Frequent state updates can lead to performance issues in React applications. When the state changes, React will re-render the component and all its child components, which could become expensive if there are many updates or if the component tree is deep. This can result in UI jank, slower render times, and poor user experience. Optimizations like using shouldComponentUpdate
, React.memo
, and useMemo
can help mitigate these issues.
useLayoutEffect
hook in React?Answer: useLayoutEffect
is similar to useEffect
, but it runs synchronously after all DOM mutations. It is executed before the browser repaints the screen, making it ideal for tasks like measuring DOM elements or making changes that need to be reflected immediately (e.g., setting up animations, modifying layout). Unlike useEffect
, which is asynchronous, useLayoutEffect
can block the paint cycle, potentially affecting performance if used excessively.
Answer: Advantages:
Limitations:
Answer: React itself does not handle asynchronous operations directly, but you can use JavaScript’s asynchronous features (e.g., Promises, async/await) within components. Managing async operations in React often involves:
useEffect
hook for side-effects like data fetching or subscribing to services.useReducer
or state management libraries like Redux can be used to manage async actions with middleware like Redux Thunk or Redux Saga.Answer:
Answer: Managing large-scale applications in React presents challenges like:
useReducer
can help centralize and organize state.componentDidMount()
and useEffect()
in terms of functionality and behavior?Answer:
componentDidMount()
is a lifecycle method used in class components. It is invoked once, immediately after a component is mounted, and is often used for tasks like data fetching or DOM manipulations.useEffect()
is a hook used in functional components. It can be configured to run on every render or only once after the component mounts (using an empty dependency array). useEffect()
is more flexible and replaces multiple lifecycle methods, including componentDidMount
, componentDidUpdate
, and componentWillUnmount
.