25 Fresh, Important Questions to Master Your React Interview
React.memo is used for functional components to prevent re-renders if props are unchanged, while PureComponent is for class components and performs a shallow comparison of props and state. Knowing the difference shows your understanding of React's rendering optimization.
// React.memo for functional component
const MyComponent = React.memo(({ value }) => {
console.log('Rendering');
return <div>{value}</div>;
});
// PureComponent for class component
class MyPureComponent extends React.PureComponent {
render() {
console.log('Rendering');
return <div>{this.props.value}</div>;
}
}
Shows your ability to optimize rendering in both functional and class components.
Multiple useEffect calls can be used to separate concerns (e.g., one for data fetching, another for event listeners). Ensure proper cleanup in each to avoid memory leaks. This question tests your ability to organize side effects.
import { useEffect, useState } from 'react';
function Component() {
const [data, setData] = useState(null);
const [width, setWidth] = useState(window.innerWidth);
// Effect for fetching data
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(setData);
}, []);
// Effect for window resize
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return <div>{data ? data.name : 'Loading...'} | Width: {width}</div>;
}
Demonstrates clean code organization and proper cleanup of side effects.
useReducer manages complex state logic with a reducer function, ideal when state transitions depend on actions or involve multiple sub-values. It's preferred over useState for complex state updates, like form handling or game logic.
import { useReducer } from 'react';
const initialState = { count: 0, step: 1 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + state.step };
case 'setStep':
return { ...state, step: action.payload };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<input
type="number"
value={state.step}
onChange={(e) => dispatch({
type: 'setStep',
payload: Number(e.target.value)
})}
/>
<button onClick={() => dispatch({ type: 'increment' })}>
Add
</button>
</div>
);
}
Shows your ability to handle complex state logic, a common requirement in real-world apps.
Debouncing delays function execution to optimize performance (e.g., for search inputs). A custom hook for debouncing shows your ability to encapsulate reusable logic.
import { useState, useEffect } from 'react';
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
function SearchInput() {
const [input, setInput] = useState('');
const debouncedInput = useDebounce(input, 500);
useEffect(() => {
console.log('Search for:', debouncedInput);
}, [debouncedInput]);
return (
<input
value={input}
onChange={(e) => setInput(e.target.value)}
/>
);
}
Tests your ability to create reusable hooks and optimize user input handling.
Accessibility ensures apps are usable by people with disabilities. Use semantic HTML, ARIA attributes, and focus management. This is critical for real-world apps and shows awareness of inclusive design.
function AccessibleForm() {
return (
<form aria-labelledby="form-title">
<h2 id="form-title">Login Form</h2>
<label htmlFor="username">Username</label>
<input id="username" aria-required="true" />
<button type="submit" aria-label="Submit form">
Submit
</button>
</form>
);
}
Highlights your understanding of web standards and user inclusivity.
The dependency array in useEffect controls when the effect runs. If empty ([]
), it runs once on mount. If it includes variables, the effect runs when those variables change. Missing dependencies can cause bugs.
import { useEffect, useState } from 'react';
function Example({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(`https://api.example.com/data/${id}`)
.then(res => res.json())
.then(setData);
}, [id]); // Runs when `id` changes
return <div>{data ? data.name : 'Loading...'}</div>;
}
Tests your understanding of how to control side effects and avoid common bugs.
Dynamic forms involve managing an array of inputs in state, often using map to render inputs and updating state based on input names or indices. This tests your ability to manage complex form state.
import { useState } from 'react';
function DynamicForm() {
const [inputs, setInputs] = useState([{ id: 1, value: '' }]);
const addInput = () => setInputs([
...inputs,
{ id: inputs.length + 1, value: '' }
]);
const handleChange = (id, value) => {
setInputs(inputs.map(input =>
input.id === id ? { ...input, value } : input
));
};
return (
<div>
{inputs.map(input => (
<input
key={input.id}
value={input.value}
onChange={(e) => handleChange(input.id, e.target.value)}
/>
))}
<button onClick={addInput}>Add Input</button>
</div>
);
}
Common in real-world apps like surveys or multi-field forms.
useImperativeHandle customizes the instance value exposed by a ref when using forwardRef. It's used in rare cases when a parent component needs to control a child component's methods.
import { useRef, useImperativeHandle, forwardRef } from 'react';
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
focus: () => console.log('Child focused'),
}));
return <div>Child Component</div>;
});
function Parent() {
const childRef = useRef();
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.focus()}>
Focus Child
</button>
</div>
);
}
Tests advanced knowledge of ref handling and component communication.
For large lists, use virtualization (e.g., react-window or react-virtualized) to render only visible items, reducing DOM load. Also, ensure unique key props and memoize components.
import { FixedSizeList } from 'react-window';
function LargeList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>{items[index]}</div>
);
return (
<FixedSizeList
height={400}
width={300}
itemCount={items.length}
itemSize={35}
>
{Row}
</FixedSizeList>
);
}
Shows your ability to handle performance issues in data-heavy apps.
Use WebSockets or libraries like socket.io with useEffect to listen for real-time updates and update state. Cleanup the connection on unmount to avoid leaks.
import { useState, useEffect } from 'react';
import io from 'socket.io-client';
function RealTimeChat() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = io('https://example.com');
socket.on('message', (message) => {
setMessages((prev) => [...prev, message]);
});
return () => socket.disconnect();
}, []);
return (
<div>
{messages.map((msg, i) => (
<p key={i}>{msg}</p>
))}
</div>
);
}
Tests your ability to integrate real-time features, common in chat or dashboard apps.
Code splitting divides your app's JavaScript bundle into smaller chunks, loading only what's needed. It improves initial load time. React supports this with React.lazy and Suspense.
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
Shows knowledge of performance optimization for large apps.
Use an <input type="file"> and the FormData API to handle file uploads. Manage the file in state and send it to a server via an API call.
import { useState } from 'react';
function FileUpload() {
const [file, setFile] = useState(null);
const handleUpload = async () => {
const formData = new FormData();
formData.append('file', file);
await fetch('/upload', {
method: 'POST',
body: formData
});
};
return (
<div>
<input
type="file"
onChange={(e) => setFile(e.target.files[0])}
/>
<button onClick={handleUpload}>Upload</button>
</div>
);
}
Common in apps requiring user uploads, like profile pictures or documents.
useTransition
, useImperativeHandle
, and virtualization test your knowledge of modern React features and performance optimization.useReducer
vs. useState
).useTransition
and concurrent rendering.