Lazy loading is particularly useful for large components, routes, or third-party libraries.
38. How does SSR handle API calls, and what considerations must be taken into account for SEO optimization?
In SSR, API calls must be made on the server during the rendering phase, often inside functions like getServerSideProps (Next.js) or similar SSR lifecycle methods. The server fetches the data, renders the page, and then sends the fully rendered HTML to the client.
SEO Considerations:
Ensure the necessary meta tags (title, description, OpenGraph, etc.) are dynamically populated with relevant content for search engines.
Ensure that data required for SEO is available at the time of server-side rendering to avoid missing metadata.
39. How can you implement a custom hook for reusable state management, and what are the benefits?
Custom hooks allow you to extract and reuse logic for state management across multiple components. This promotes code reuse and keeps your components clean and focused on rendering.
Benefits include encapsulation of logic, better code organization, and reusability across different components.
40. Virtual DOM
The Virtual DOM may still lead to performance bottlenecks for very large UIs, as the diffing algorithm could become expensive for complex trees.
In high-priority tasks (like animations or user inputs), updates could be delayed.
React Concurrent Mode: Concurrent Mode helps address these limitations by allowing React to interrupt long-running tasks (like rendering) to prioritize more urgent updates. This leads to a more responsive UI.
Example: In Concurrent Mode, React can break down large rendering tasks into smaller units, rendering portions of the tree in a non-blocking way, prioritizing more critical updates over less important ones.
41. What are some common pitfalls when using Higher-Order Components, and how can you avoid them?
Common pitfalls with HOCs include:
Loss of displayName: Wrapped components lose their displayName, making debugging harder. You can fix this by manually setting the displayName of the HOC.
Prop Collisions: The HOC might unintentionally overwrite or conflict with the props passed to the wrapped component. This can be avoided by using distinct prop names or spreading only relevant props.
42. What is the useReducer Hook, and how does it differ from useState? Provide an example of when to use it.
useReducer is an alternative to useState for managing complex state logic, especially when the next state depends on the previous one or when there are multiple state transitions.
Difference:
useState is good for simple, independent state changes.
useReducer is better suited for more complex state transitions, especially when an action affects multiple pieces of state or when state logic is centralized.
43. How can you create custom JSX elements and what are the limitations?
Create custom JSX elements by defining a function or class that returns JSX. The function name should start with an uppercase letter so React can differentiate it from standard HTML tags.
Example:
function MyButton({ label }) {
return ;
}
Limitations:
Custom elements must be either function or class components. They cannot be just plain objects or arrays.
JSX expressions must have a single root element.
44. How can you handle multiple contexts in a component, and what patterns can help manage this complexity?
To handle multiple contexts, you can use multiple useContext hooks or nest Context.Provider components.
Compound components pattern: Group related context providers together to simplify the API and avoid deeply nested Provider components.
Custom hooks: Abstract multiple context values into a custom hook for better reusability.
45. How can you validate complex props with propTypes and why is it important?
Prop validation ensures that components receive the correct types and structure of props, reducing bugs. You can use propTypes to validate complex data structures, such as objects with specific shapes or arrays of objects.
Error boundaries cannot catch errors in event handlers because error boundaries only catch errors during rendering, lifecycle methods, and constructors. To catch errors in event handlers, you should use try-catch blocks.
Example:
function handleClick() {
try {
// Code that may throw
} catch (error) {
console.error(error);
}
}
return ;
Event handler errors do not affect the rendering process, so they need to be handled separately.
47. How can you optimize large lists in React for better performance?
For large lists, performance can degrade because React renders all the items at once. You can optimize large lists using:
Virtualization (react-window or react-virtualized): Renders only the visible part of the list to the user, reducing the number of rendered DOM nodes.
Example with react-window:
import { FixedSizeList as List } from ‘react-window’;
const MyList = () => (
{({ index, style }) =>
Item {index}
}
);
Virtualization significantly improves performance by rendering only the visible items and recycling DOM nodes for off-screen items.
48. 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.
49. How does React’s useContext compare to using a state management library like Redux, and when should you use each?
useContext: Best for small to medium-sized apps where state management is localized. It’s easy to implement and comes built into React, making it ideal for apps with limited global state needs.
Redux: Better for large-scale applications with complex state logic, requiring middleware, dev tools, and a more structured state management approach.
When to use each:
Use useContext for small apps with limited global state and few side effects.
Use Redux for large apps where multiple components need access to deeply nested state, or when the state requires advanced management features like middleware for async actions.
50. 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.