Advanced React interviews questions

1. What are React Hooks and how do they work?

Answer: React Hooks are functions that let you use state and other React features without writing a class. They were introduced in React 16.8.

Example:

import React, { useState, useEffect } from 'react';

function Example() {
const [count, setCount] = useState(0);

useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

2. Explain the useEffect Hook and its usage.

Answer: The useEffect Hook lets you perform side effects in function components. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes.

Example:

import React, { useEffect } from 'react';

function Example() {
useEffect(() => {
console.log('Component did mount');
return () => {
console.log('Component will unmount');
};
}, []);

return <div>Check the console logs</div>;
}

3. How do you optimize performance in a large React application?

Answer: Performance optimization in React can be achieved through various techniques such as memoization, code splitting, lazy loading, and avoiding unnecessary re-renders using React.memo and useCallback.

Example:

import React, { useState, useCallback } from 'react';

const ExpensiveComponent = React.memo(({ compute }) => {
console.log('Expensive component rendered');
return <div>Result: {compute()}</div>;
});

function App() {
const [count, setCount] = useState(0);

const compute = useCallback(() => {
return count * 2;
}, [count]);

return (
<div>
<ExpensiveComponent compute={compute} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

4. What is the Context API and how is it used?

Answer: The Context API allows you to pass data through the component tree without having to pass props down manually at every level.

Example:

import React, { createContext, useContext } from 'react';

const MyContext = createContext();

function ComponentA() {
return (
<MyContext.Provider value="Hello, World!">
<ComponentB />
</MyContext.Provider>
);
}

function ComponentB() {
return <ComponentC />;
}

function ComponentC() {
const value = useContext(MyContext);
return <div>{value}</div>;
}

5. Describe the useReducer Hook and its benefits.

Answer: The useReducer Hook is used for state management in React when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

Example:

import React, { useReducer } from 'react';

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' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}

6. How can you handle forms in React?

Answer: Handling forms in React involves using controlled components where form data is handled by the component’s state.

Example:

import React, { useState } from 'react';

function MyForm() {
const [name, setName] = useState('');

const handleSubmit = (event) => {
event.preventDefault();
alert(`Form submitted with name: ${name}`);
};

return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
<button type="submit">Submit</button>
</form>
);
}

7. What is the difference between controlled and uncontrolled components?

Answer: Controlled components are those where form data is handled by the component’s state, whereas uncontrolled components rely on the DOM to handle form data.

Example (Controlled):

import React, { useState } from 'react';

function ControlledComponent() {
const [value, setValue] = useState('');

return (
<input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
);
}

Example (Uncontrolled):

import React, { useRef } from 'react';

function UncontrolledComponent() {
const inputRef = useRef();

const handleClick = () => {
alert(`Input value: ${inputRef.current.value}`);
};

return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleClick}>Alert Input Value</button>
</div>
);
}

8. Explain the concept of Higher-Order Components (HOC).

Answer: A Higher-Order Component (HOC) is a function that takes a component and returns a new component, enhancing the original component with additional props or behavior.

Example:

import React from 'react';

function withLogger(WrappedComponent) {
return function EnhancedComponent(props) {
console.log('Rendering', WrappedComponent.name);
return <WrappedComponent {...props} />;
};
}

function MyComponent() {
return <div>My Component</div>;
}

const MyComponentWithLogger = withLogger(MyComponent);

9. What is React Suspense and how does it work?

Answer: React Suspense is a feature for managing asynchronous operations in a declarative way. It allows you to specify the loading state of part of your component tree.

Example:

import React, { Suspense } from 'react';

const LazyComponent = React.lazy(() => import('./LazyComponent'));

function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}

10. How do you manage side effects in a functional component?

Answer: Side effects in a functional component are managed using the useEffect Hook. This Hook allows you to perform actions like data fetching, subscriptions, and manual DOM manipulations after the component renders.

Example:

import React, { useEffect, useState } from 'react';

function DataFetcher() {
const [data, setData] = useState(null);

useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []);

return (
<div>
{data ? <div>Data: {JSON.stringify(data)}</div> : <div>Loading...</div>}
</div>
);
}

11. Explain the purpose and usage of React.memo.

Answer: React.memo is a higher-order component that memoizes the rendered output of a function component. It helps to optimize performance by preventing unnecessary re-renders if the props have not changed.

Example:

import React from 'react';

const MyComponent = React.memo(({ name }) => {
console.log('Rendering MyComponent');
return <div>{name}</div>;
});

function App() {
const [name, setName] = useState('John');

return (
<div>
<MyComponent name={name} />
<button onClick={() => setName('John')}>Set Name to John</button>
</div>
);
}

12. What is the difference between useState and useReducer?

Answer: useState is suitable for simple state management, while useReducer is preferable for complex state logic that involves multiple sub-values or when the next state depends on the previous one.

Example (useState):

import React, { useState } from 'react';

function Counter() {
const [count, setCount] = useState(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Example (useReducer):

import React, { useReducer } from 'react';

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' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}

13. How do you handle error boundaries in React?

Answer: Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI.

Example:

import React, { Component } from 'react';

class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
return { hasError: true };
}

componentDidCatch(error, errorInfo) {
console.error("Error caught:", error, errorInfo);
}

render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}

return this.props.children;
}
}

function MyComponent() {
throw new Error("I crashed!");
return <div>My Component</div>;
}

function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}

14. What are render props in React?

Answer: Render props are a technique for sharing code between React components using a prop whose value is a function. A component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.

Example:

import React, { Component } from 'react';

class Mouse extends Component {
constructor(props) {
super(props);
this.state = { x: 0, y: 0 };
}

handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};

render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}

function App() {
return (
<Mouse render={({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
)} />
);
}

15. How can you achieve code splitting in a React application?

Answer: Code splitting in a React application can be achieved using dynamic import() and React’s React.lazy for lazy loading components. This helps in reducing the initial load time of the application.

Example:

import React, { Suspense } from 'react';

const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}

16. Explain the significance of keys in React lists.

Answer: Keys help React identify which items have changed, are added, or are removed. They should be given to the elements inside the array to give the elements a stable identity.

Example:

import React from 'react';

function List({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}

17. What is the useLayoutEffect Hook and how does it differ from useEffect?

Answer: useLayoutEffect fires synchronously after all DOM mutations. You can use it to read layout from the DOM and synchronously re-render. It’s similar to useEffect, but it fires before the browser repaints the screen.

Example:

import React, { useLayoutEffect, useRef } from 'react';

function LayoutEffectComponent() {
const divRef = useRef();

useLayoutEffect(() => {
console.log('useLayoutEffect: Div width is', divRef.current.offsetWidth);
});

return <div ref={divRef}>Check console for layout effect</div>;
}

18. How do you create a custom hook in React?

Answer: A custom hook is a function that starts with “use” and may call other hooks inside it. It allows you to extract component logic into reusable functions.

Example:

import { useState, useEffect } from 'react';

function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);

useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return width;
}

function App() {
const width = useWindowWidth();

return <div>Window width: {width}</div>;
}

19. Explain the use of the forwardRef function.

Answer: forwardRef is a React function that allows you to forward refs to child components. It’s used to pass refs through component layers.

Example:

import React, { forwardRef } from 'react';

const FancyButton = forwardRef((props, ref) => (
<button ref={ref} className="fancy-button">
{props.children}
</button>
));

function App() {
const buttonRef = React.createRef();

return (
<FancyButton ref={buttonRef}>Click me!</FancyButton>
);
}

20. How do you handle asynchronous data fetching in React with hooks?

Answer: Asynchronous data fetching in React can be handled using the useEffect hook along with async functions.

Example:

import React, { useState, useEffect } from 'react';

function DataFetcher() {
const [data, setData] = useState(null);

useEffect(() => {
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
}

fetchData();
}, []);

return (
<div>
{data ? <div>Data: {JSON.stringify(data)}</div> : <div>Loading...</div>}
</div>
);
}

Let me know if you need more batches!