1. Describe how React Context API can be used for state management in an app
So, you’re tired of prop-drilling your app to death? Welcome to the beautiful world of React Context API.
When should you use Context API
Use it when:
- You need to share state across many components.
- You want to avoid third-party state managers for smaller apps.
Setting up a context
import { createContext, useState } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState("dark");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
Accessing and updating context values
import { useContext } from 'react';
import { ThemeContext } from './context/ThemeContext';
const ThemeSwitcher = () => {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Toggle Theme
</button>
);
};
2. What is the role of React Router, and how does it work with dynamic routing?
React Router = GPS of your React App.
Dynamic route parameters
<Route path="/user/:id" element={<User />} />
import { useParams } from 'react-router-dom';
const User = () => {
const { id } = useParams();
return <div>User ID is {id}</div>;
};
Using useNavigate
const navigate = useNavigate();
navigate('/dashboard');
3. Explain the concept of controlled and uncontrolled components in React
Controlled:
const [value, setValue] = useState('');
<input value={value} onChange={(e) => setValue(e.target.value)} />
Uncontrolled:
const inputRef = useRef();
<input ref={inputRef} />
<button onClick={() => console.log(inputRef.current.value)}>Log</button>
4. How would you optimize React app performance when handling large lists or grids?
Use virtualization:
import { FixedSizeList as List } from 'react-window';
<List height={400} itemCount={1000} itemSize={35} width={300}>
{({ index, style }) => <div style={style}>Row {index}</div>}
</List>
Memoization:
React.memo
,useMemo
,useCallback
5. Explain the difference between shallow and deep comparison in React’s shouldComponentUpdate
- Shallow comparison only checks surface level.
- Deep comparison checks nested structures.
- Always avoid mutating objects to let React detect changes.
6. How do you handle asynchronous code execution and state updates in React?
With useEffect
:
useEffect(() => {
const fetchData = async () => {
const res = await fetch("/api/data");
const json = await res.json();
setData(json);
};
fetchData();
}, []);
Avoid race conditions with AbortController
7. How would you implement custom hooks to abstract logic in React?
useFetch Example:
const useFetch = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url).then(res => res.json()).then(setData);
}, [url]);
return data;
};
8. What are higher-order components (HOCs) in React, and how are they used?
const withLogger = (Component) => {
return (props) => {
console.log("Props:", props);
return <Component {...props} />;
};
};
Common use cases: withAuth
, connect()
from Redux
9. How would you implement a search feature with debouncing in React?
Using lodash.debounce:
import debounce from 'lodash.debounce';
const handleSearch = debounce((query) => {
fetch(`/api/search?q=${query}`);
}, 300);
<input onChange={(e) => handleSearch(e.target.value)} />
10. Explain React’s reconciliation process and how it updates the DOM efficiently
React’s reconciliation process is its way of figuring out what changed in the UI and updating only those parts of the DOM — not the whole thing. This magic happens thanks to the Virtual DOM, a lightweight copy of the real DOM that React keeps in memory.
Whenever state or props change, React creates a new Virtual DOM tree and compares it to the previous one using a diffing algorithm. This comparison is lightning-fast because React uses heuristics like assuming components with the same key and type are the same — to skip unnecessary checks.
If differences are found, React calculates the minimal set of changes needed and applies them to the actual DOM using efficient batch updates. This is much faster than re-rendering everything, which is what older frameworks used to do. React also batches state updates and avoids layout thrashing by updating DOM elements outside the layout/render cycle.
In simple terms: React is like a super-smart detective that notices what changed, where, and updates just that part — like fixing one tile on a floor instead of retiling the whole room. This results in high performance, smooth rendering, and a better user experience.
This makes React super fast and efficient.