100 React Inteview Questions
100 React Inteview Questions
Differences:
Virtual DOM: React maintains a virtual representation of the DOM to update only
the necessary parts of the UI, enhancing performance compared to traditional DOM
manipulation.
Unidirectional Data Flow: Unlike some libraries with two-way data binding, React
follows a one-way data flow, making the data flow and application state easier to
understand and debug.
JSX: JavaScript XML (JSX) allows writing HTML within JavaScript, making the syntax more
concise and readable.
Extensions: Tools like React Router and Redux provide routing and state management
for larger applications.
Purpose:
javascript
// Example of JSX
const element = <h1>Hello, world!</h1>; // Renders a heading in React
Structure:
javascript
Don’t have lifecycle methods but can use hooks (e.g., useState , useEffect ) to
manage state and lifecycle.
Class Components:
Usage: Props are read-only and cannot be modified by the receiving component.
javascript
// Passing props
function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}
Purpose:
State changes trigger re-renders, updating the UI to reflect the new data.
Unlike props, state is local to the component and can be modified within it.
Used for data that should remain constant throughout the component's lifecycle.
State:
With props:
javascript
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
10. What Are React Fragments, and Why Are They Useful?
Definition: React Fragments allow grouping of multiple elements without adding an
extra DOM node.
Usefulness:
Avoids unnecessary <div> wrappers, which helps with cleaner HTML structure and
CSS styling.
javascript
function List() {
return (
<>
<li>Item 1</li>
<li>Item 2</li>
</>
);
}
Key Takeaways:
Components, props, and state form the core concepts, allowing modular, dynamic data-
driven applications.
Functional components with hooks are now favored over class components.
JSX and React fragments simplify component structure and improve code readability.
Here are detailed explanations for each question on React concepts, presented in a
structured format:
Purpose:
Performance Optimization: Keys help React identify which items have changed,
been added, or removed. This reduces the number of re-renders by efficiently
updating only the necessary elements.
Best Practices:
Avoid using indexes as keys, as they can lead to issues when the list items are
reordered or updated.
javascript
Phases:
Mounting: When the component is created and inserted into the DOM.
javascript
componentDidUpdate(prevProps, prevState) {
console.log("Component updated");
}
componentWillUnmount() {
console.log("Component will unmount");
}
render() {
return <h1>{this.state.count}</h1>;
}
}
Purpose:
Example:
javascript
javascript
// Parent component
function ParentComponent() {
return <ChildComponent message="Hello" />;
}
// Child component
function ChildComponent(props) {
return <h1>{props.message}</h1>;
}
Child to Parent (Callback Functions): Pass a function from the parent to the child,
allowing the child to call this function and send data back to the parent.
javascript
// Parent component
function ParentComponent() {
const handleChildData = (data) => {
console.log("Data from child:", data);
};
// Child component
function ChildComponent(props) {
return (
<button onClick={() => props.sendData("Hello from child!")}>
Send Data
</button>
Between Sibling Components: Use a shared parent component to manage state and
pass data as props to both child components, or use a state management library (e.g.,
Redux, Context API) for larger applications.
Basic Hooks:
Example:
javascript
function Counter() {
const [count, setCount] = useState(0); // Declare state variable
"count"
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Example:
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return <h1>{count}</h1>;
}
Summary of Hooks:
Hooks bring powerful features like state and lifecycle methods to functional components.
Common hooks ( useState , useEffect ) cover state and effects, while other hooks (like
useContext ) provide additional functionality.
Important: Hooks must be used at the top level of the component function and cannot
be used inside loops or conditionals.
Basic Usage:
The useState function takes an initial value as an argument and returns an array
with two items:
Syntax:
javascript
Example:
javascript
function Counter() {
const [count, setCount] = useState(0); // count initialized to 0
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
In this example, count is the state variable, and setCount is the function used to
update count . Clicking the button increments count by 1.
Key Point: useState helps add state management to functional components without
needing class components.
Basic Usage:
useEffect takes a function as its first argument. This function runs after the
component renders or when specific dependencies change.
A second optional argument, the dependency array, controls when the effect
should re-run.
Syntax:
javascript
useEffect(() => {
// Code for the side effect
return () => {
// Cleanup code (optional)
};
}, [dependencies]);
Example:
javascript
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return <h1>{count}</h1>;
}
Key Point: useEffect makes it easy to handle side effects in functional components, similar
to lifecycle methods in class components.
How It Works:
React creates a virtual copy of the DOM and updates it when the component’s state
or props change.
Diffing Algorithm: React compares the updated virtual DOM to the previous version
using a diffing algorithm to identify changes.
Efficient Updates: Only the modified elements are updated in the real DOM,
reducing the rendering cost.
Benefits:
Example Workflow:
Key Point: The virtual DOM improves app performance by minimizing costly DOM operations,
especially in large applications.
Usage:
Ensures that components have default values for props, preventing issues if the
parent component forgets to pass a required prop.
Example:
javascript
Greeting.defaultProps = {
name: "Guest"
};
Key Point: defaultProps simplifies component usage by providing fallback values, ensuring
reliable rendering.
Basic Usage:
Example:
javascript
Here, the message displays only if message is not an empty or null value.
Key Point: Conditional rendering tailors UI responses based on state or props, enhancing
user experience by showing relevant content.
Each concept provides a foundation for React’s approach to building interactive UIs. Hooks
( useState and useEffect ) simplify adding state and side effects in functional components,
while the Virtual DOM enhances efficiency. Conditional rendering and default props help
build more responsive, flexible applications.
Key Points:
React events are similar to regular JavaScript events but follow camelCase syntax
(e.g., onClick instead of onclick ).
Use synthetic events in React, a cross-browser wrapper around the browser's native
events.
Example:
javascript
function Button() {
const handleClick = () => {
alert("Button clicked!");
};
Key Point: React’s event handling provides a consistent API across browsers, enhancing the
development experience.
Value is stored in the component’s state, and changes are managed by React.
Uncontrolled Components:
Form input’s value is accessed via a ref, letting the DOM manage the value without
linking it to the component’s state.
javascript
function ControlledInput() {
const [inputValue, setInputValue] = useState("");
return (
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
);
}
javascript
function UncontrolledInput() {
const inputRef = useRef(null);
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
Example:
javascript
function Form() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
Key Point: Handling forms with React state makes form data easily accessible and
manageable, especially for dynamic validation or conditional rendering.
Usage:
Useful for global or shared data like theme, user authentication, or settings.
Example:
javascript
// Create a Context
const ThemeContext = React.createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return <ThemeButton />;
}
Key Point: useContext provides an efficient way to share data across components without
passing props down multiple levels.
Basic Usage:
useRef returns an object with a .current property, which can store mutable
values or DOM elements.
Typically used to access DOM nodes directly, store previous values, or set up
persistent data that does not need to trigger a re-render.
javascript
function FocusInput() {
const inputRef = useRef(null);
javascript
function Timer() {
const count = useRef(0);
useEffect(() => {
const interval = setInterval(() => {
count.current += 1;
console.log(count.current); // Logs without causing re-renders
}, 1000);
Key Point: useRef is useful for accessing and modifying DOM elements directly and storing
values that persist without triggering re-renders.
React’s event handling and form management streamline user interaction, while
useContext and useRef help manage state and component structure more effectively.
Key Process:
Diffing Algorithm: When the state or props change, React updates the virtual DOM
and compares it with the previous version. Only the differences are identified.
Efficient Updates: React batches and applies only the minimal set of changes (called
"patches") to the real DOM, improving performance.
Benefits:
Key Point: React’s virtual DOM and reconciliation process allow it to update only what’s
necessary, resulting in faster, more efficient UI updates.
Purpose:
Syntax:
javascript
Example:
javascript
Key Point: HOCs allow code reuse and separation of concerns, making components more
modular and flexible.
Basic Usage:
An initial state.
Syntax:
javascript
Example:
javascript
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>
);
}
Here, the dispatch function triggers actions that the reducer function uses to
update the state.
29. Explain the Difference Between React’s context API and Props
Definition:
Props: Used to pass data from a parent component to a child component. Props are
immutable within the child and must be explicitly passed down.
Context: Provides a way to share data across many levels of the component tree
without having to pass props at every level (known as prop drilling).
Differences:
Use Case:
Context: Best for global data needed by many components, such as theme,
authentication status, or language preference.
Accessibility:
Context: Any component wrapped in a context provider can access data without
direct prop passing.
Example:
javascript
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
function ThemedButton() {
const theme = useContext(ThemeContext); // Access data from context
return <button className={theme}>Theme Button</button>;
}
Key Point: Use props for specific data passing and context for globally relevant data, reducing
prop drilling in deeply nested components.
Usage:
It enables component composition, letting you pass child elements directly within
the component’s opening and closing tags.
Example:
javascript
function App() {
return (
<Container>
<h1>Hello World!</h1>
<p>This is inside the container.</p>
</Container>
Here, Container renders whatever content is placed between its opening and
closing tags.
Key Point: The children prop makes components more flexible and reusable, allowing them
to serve as wrappers for any nested content.
In summary, React’s DOM update mechanism, HOCs, and hooks ( useReducer , useContext ,
useRef ) provide powerful tools for building responsive, modular UIs. The context API vs.
props and children prop enhance data sharing and composition, simplifying component
interactions and data management.
Common Techniques:
Memoization:
Use useMemo and useCallback hooks to cache values and functions, reducing
unnecessary recalculations.
Code Splitting:
Use React’s React.lazy and dynamic imports to split code and load only
necessary components.
Define functions outside JSX to prevent new function instances being created on
each render.
Key Point: Optimizing React performance ensures faster load times and smoother
interactions, especially in complex applications.
Functionality:
React Router uses the browser’s history API to enable client-side routing.
Basic Setup:
javascript
function App() {
return (
<BrowserRouter>
Here, Home and About components render based on the URL path.
Key Point: React Router makes single-page applications (SPAs) feel like multi-page websites,
enhancing navigation without full-page reloads.
Methods:
Example:
javascript
function Home() {
Key Point: Programmatic navigation is useful for conditional redirects, such as after form
submission or authentication.
Implementation:
React’s React.lazy and Suspense are used to split components into separate
chunks that load when needed.
Syntax:
javascript
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Route path="/about" component={About} />
</Suspense>
);
}
Benefits:
Reduces initial page load time by splitting and deferring the loading of non-essential
components.
Key Point: Lazy loading optimizes performance by loading only what’s necessary, leading to
faster and more efficient applications.
Characteristics:
Shallow Comparison: Pure components use shallow comparison of props and state
to prevent unnecessary re-renders.
Implementation:
javascript
When to Use:
Use for components with simple, predictable props that change infrequently.
Key Point: Pure components help optimize performance by preventing re-renders when the
data hasn’t changed, making them ideal for reusable, static-like elements.
React performance optimizations and lazy loading enhance efficiency, while React Router
and programmatic navigation improve user navigation in SPAs. Pure components are a key
strategy for reducing unnecessary re-renders, keeping applications fast and responsive.
Problem:
Prop drilling can make the component tree complex, harder to read, and difficult to
manage.
Solutions:
Context API:
Example:
javascript
function App() {
return (
<ThemeContext.Provider value="dark">
function ComponentC() {
const theme = useContext(ThemeContext);
return <div>{theme}</div>;
}
Tools like Redux or Recoil manage global state, making data available to any
component without prop drilling.
Composition Patterns:
Key Point: Avoiding prop drilling improves code readability and makes data access more
straightforward in deeply nested components.
React Implementation:
React.memo:
Useful for components with stable props or that only re-render based on
specific changes.
Key Point: Memoization is critical for enhancing performance in React by caching results,
preventing redundant computations, and minimizing re-renders.
Syntax:
javascript
Use Cases:
Example:
javascript
function ExpensiveComponent({ a, b }) {
const computed = useMemo(() => {
console.log("Computing...");
return a + b;
}, [a, b]);
Key Point: Use useMemo to optimize performance for values that require expensive
calculations, improving the efficiency of component re-renders.
Characteristics:
The onChange event handler updates the state, and the input value is set to match
the state.
Advantages:
Example:
javascript
function Form() {
const [name, setName] = useState("");
return (
<input type="text" value={name} onChange={handleChange} />
Here, the input field is controlled by name , and every change updates name via
handleChange .
Key Point: Controlled components make it easier to manage form data and handle validation
by keeping the form values synchronized with the component’s state.
Function:
Example:
javascript
This creates a <h1> element with a class of "greeting" and the text content "Hello,
world!".
Key Point: React.createElement() is a fundamental function that powers JSX, creating virtual
DOM nodes for rendering components and elements.
Example:
javascript
PureComponent:
javascript
42. How Does the useCallback Hook Work, and When Should It Be
Used?
Definition: useCallback is a React hook that memoizes a function, returning the same
function instance between renders unless its dependencies change.
Syntax:
javascript
Use Cases:
Example:
javascript
Key Point: Use useCallback to memoize functions and prevent unnecessary re-creation,
improving performance and avoiding re-renders in child components dependent on these
functions.
Modals and Dialogs: Render modals outside the main app’s DOM structure, typically
to avoid z-index or overflow issues.
Tooltips and Popovers: Place components outside the usual hierarchy for better
control over positioning and visibility.
Example:
javascript
In this example, the Modal component renders to a different part of the DOM
( modal-root ), not within the usual component hierarchy.
Key Point: Use portals to render components outside the main DOM tree when working with
elements like modals, tooltips, or popovers, especially to solve layout or overflow issues.
Identify the closest common ancestor that should manage the shared state.
Move the state and any associated functions to that ancestor component.
Example:
javascript
function ParentComponent() {
const [sharedValue, setSharedValue] = useState("");
return (
<>
<ChildA value={sharedValue} setValue={setSharedValue} />
<ChildB value={sharedValue} />
</>
);
}
Key Point: Lifting state up promotes better data management and synchronization across
related components by managing shared state in a common ancestor.
Implementation:
javascript
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log("Error:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Usage:
javascript
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
Limitations:
Error Handling Libraries: Tools like Sentry can be integrated with React to log and
monitor errors.
Key Point: Error boundaries provide a way to catch and handle render-phase errors, ensuring
components with errors don’t crash the entire app.
Functionality:
Used within an Error Boundary to catch and handle errors during the rendering
phase, in lifecycle methods, and in constructors of child components.
Example:
javascript
render() {
Key Point: componentDidCatch() is essential for gracefully handling runtime errors in React
applications, preventing a full app crash.
Example:
javascript
setState(newValue);
console.log(state); // state logs the updated value immediately.
Asynchronous Updates:
React batches state updates and handles them asynchronously within event
handlers.
Note: With React’s concurrency features, most state updates are asynchronous even
if they seem synchronous.
Example:
javascript
setState(newValue);
console.log(state); // state logs the old value due to batching.
How It Works:
2. Provide a Context Value using <Provider> at the top level where data is needed.
Example:
javascript
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return <div>{theme}</div>;
}
Use Cases:
Ideal for global state like user authentication, theme settings, or language
preferences.
49. What Are Side Effects, and How Are They Handled in React?
Definition: A side effect is any action or operation that affects something outside the
scope of the function it’s in, like data fetching, subscriptions, or manipulating the DOM.
useEffect Hook:
Accepts two arguments: a function containing the side effect and an optional
dependency array that dictates when it should re-run.
Example:
javascript
useEffect(() => {
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => setData(data));
}, []); // Empty array ensures this runs only once on mount
Types of Effects:
Non-Cleanup Effects: Effects that don’t require cleanup, such as data fetching.
Cleanup Effects: Effects that do require cleanup, like subscriptions, where you
return a function to unsubscribe or clean up.
Key Point: Side effects in React are managed through useEffect , which provides control over
when these effects occur and helps maintain clean code by allowing cleanup.
How It Works:
Example:
javascript
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Use Cases:
Data Fetching: Handling component rendering until API data is available (with the
upcoming React Server Components).
Key Point: Suspense improves user experience by handling loading states gracefully, making
it essential for async data fetching and code-splitting with lazy-loaded components.
Example:
javascript
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Key Point: Code splitting enhances performance by reducing the size of initial JavaScript
bundles, making apps load faster and more efficiently.
The server generates HTML from React components and sends it to the client.
The client hydrates the HTML, attaching React event listeners to make it interactive.
javascript
Key Point: SSR improves performance and SEO by pre-rendering React components on the
server, making the app faster to display on the client.
53. What Are Hooks Rules, and Why Are They Important?
Definition: Hooks rules are guidelines to ensure hooks function correctly within React.
Rules:
1. Only Call Hooks at the Top Level: Hooks should be called directly within React
functions, not inside loops, conditions, or nested functions.
2. Only Call Hooks in React Functions: Hooks should only be used within React
functional components or custom hooks, not in regular JavaScript functions.
Importance:
These rules ensure consistent hook order across renders, enabling React to
correctly manage state and dependencies.
javascript
if (condition) {
const [count, setCount] = useState(0); // Violates hook rule
}
When to Use:
Use useLayoutEffect when you need to perform operations that directly modify
the DOM and want them to happen before the browser repaints. For instance,
adjusting dimensions or layout.
Example:
javascript
useLayoutEffect(() => {
const width = ref.current.offsetWidth;
console.log("Width:", width);
}, []);
useLayoutEffect blocks the painting process until it completes, making it useful for
operations that require immediate DOM changes, while useEffect runs after the
browser repaints.
Key Point: useLayoutEffect is best for synchronously interacting with the DOM right after
changes but before rendering, making it useful for layout adjustments and measuring
elements.
Use import() to dynamically import modules and load them only when they are
needed.
Often paired with React.lazy and Suspense for dynamically loading components.
Example:
javascript
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Benefits:
Improves Performance: Only loads code when it’s actually needed, reducing initial
bundle size.
Better User Experience: Allows loading specific parts of the app on-demand,
enhancing responsiveness.
Key Point: Dynamic imports make it easy to split and load code as needed, improving the
app’s performance and user experience by reducing initial load times.
How It Works:
Comparison:
Same Element Type: If elements have the same type, React updates only the
changed attributes.
Different Element Types: If types differ, React replaces the old element with a
new one, re-rendering the subtree.
Keyed Lists: When dealing with lists, React uses key attributes to track item
positions, improving efficiency by moving only necessary elements.
Benefits:
Minimizes actual DOM updates, making UI rendering faster and more efficient.
Key Point: The reconciliation algorithm enables React to perform optimized re-renders by
updating only modified parts of the component tree, enhancing app performance.
Importance:
Application State: The root component often manages global state or context
providers needed by the entire app.
Example:
javascript
Key Point: The root component is foundational, holding the entire application structure and
configuration, ensuring seamless data flow through nested components.
When to Use:
Useful for passing ref down to lower-level DOM elements for direct manipulation,
especially when using controlled components or third-party libraries.
Example:
javascript
function App() {
const inputRef = React.useRef();
Benefits:
Key Point: React.forwardRef is essential for giving parent components direct access to child
components’ refs, improving flexibility in handling DOM nodes.
useEffect :
useRef : Provides persistent values across renders, like instance variables in classes.
Example:
javascript
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Component mounted or updated");
return () => console.log("Cleanup on unmount");
}, [count]);
}
Key Point: React hooks simplify and streamline lifecycle management, providing a functional,
declarative way to handle component effects and state.
How It Works:
Benefits:
Identifies Side Effects: Helps catch unexpected side effects in lifecycle methods or
hooks.
Encourages Best Practices: Warns about deprecated methods, improving the code
quality and future-proofing.
Example:
javascript
<React.StrictMode>
<App />
</React.StrictMode>
Key Point: StrictMode promotes cleaner, more reliable React code by enforcing best
practices and warning about potential issues, making it an essential tool for development.
Best Practices:
Keyboard Navigation: Make all interactive elements focusable and usable via
keyboard.
Alt Text and Labels: Provide meaningful alt attributes for images and labels for
inputs.
React-Specific Tools:
React Testing Library: Use the getByRole and getByLabelText queries to verify
accessibility during testing.
Key Point: Ensuring accessibility in React involves using semantic HTML, appropriate ARIA
roles, focus management, and keyboard navigation support, providing a more inclusive
experience.
Usage:
Example:
javascript
Key Point: hydrate() optimizes SSR applications by attaching event listeners to server-
rendered HTML, enabling fast loading and interactivity without unnecessary re-renders.
Used to pass data down the component tree without prop drilling.
Suitable for simpler state management cases, such as theme settings or user data.
Redux:
A more robust state management library, especially useful for complex, large-scale
apps.
Comparison:
Complexity: Context API is simpler and built into React, while Redux has a steeper
learning curve but provides more control.
Key Point: The Context API is suitable for simpler state management within React, while
Redux is more appropriate for larger applications with complex state logic and requirements.
Large Initial Bundles: Slow load times due to large bundle sizes.
Inefficient List Rendering: Slow rendering when displaying large lists or tables.
Improper Use of Context API: Using Context in a way that causes unnecessary re-
renders in deeply nested components.
Optimization Techniques:
Code Splitting: Use dynamic imports and React.lazy to split code into smaller
bundles.
Avoiding Inline Functions and Objects: Inline values create new references on each
render, causing re-renders.
Key Point: Optimizing performance in React involves reducing unnecessary re-renders, using
memoization, and implementing code-splitting and virtualization for large data.
Fetching Example:
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await fetch('/api/data');
const result = await response.json();
setData(result);
}
fetchData();
}, []);
return <div>{data ? data : "Loading..."}</div>;
}
Error Handling:
Handle errors using try/catch within async functions or set error states within
useEffect .
Libraries like React Query and SWR manage caching, re-fetching, and error
handling more effectively, optimizing the data-fetching experience.
Key Point: React handles asynchronous operations with useEffect and async/await , while
libraries like React Query offer robust solutions for caching and complex data-fetching
needs.
In SSR, HTML is generated on the server based on the initial state and sent to the
client.
Benefits: Faster initial load, better SEO (search engines can read the content
immediately), and improved performance for users with slower devices.
In CSR, JavaScript runs on the client-side to render content after the initial page
load.
Benefits: Faster server response (sends lightweight HTML initially) and improved
interactivity and flexibility.
Comparison:
SSR improves SEO and initial load times but requires more server resources.
CSR offers a smoother and more interactive experience but can have slower initial
page loads and isn’t as SEO-friendly.
Key Point: SSR provides better SEO and faster initial loads, while CSR allows for dynamic,
highly interactive pages with reduced server load.
Usage:
Example:
javascript
Key Point: Use dangerouslySetInnerHTML only when necessary and ensure the content is
sanitized to avoid security vulnerabilities.
Impact on Reusability:
Use state lifting when child components need to share or synchronize data.
Otherwise, keep state local for isolated reusability.
Key Point: While state lifting promotes better data sharing, it can limit component reusability
by increasing dependence on parent state.
69. What Are Custom Hooks, and How Do You Create One?
Definition: Custom hooks in React are functions that allow you to encapsulate and reuse
stateful logic across multiple components.
Benefits:
Custom hooks can centralize repetitive logic, making it easier to maintain and test.
javascript
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const result = await response.json();
setData(result);
setLoading(false);
}
fetchData();
}, [url]);
Usage:
javascript
Key Point: Custom hooks enable reusable, isolated logic that can be shared across
components, improving code organization and reducing redundancy.
Used for side effects, such as data fetching, setting up subscriptions, and modifying
the DOM.
Example:
javascript
Example:
javascript
function MyComponent() {
useEffect(() => {
console.log("Component mounted");
return () => {
console.log("Cleanup on unmount");
};
}, []); // Empty array means it runs only on mount/unmount
}
Key Point: componentDidMount is specific to class components and runs once after mounting,
while useEffect in functional components can handle mounting, updating, and
unmounting, offering greater flexibility.
Implementation:
Clear the timeout on each keystroke to reset the timer, triggering the function only
after typing stops.
Example:
javascript
function DebouncedInput() {
const [input, setInput] = useState('');
const [debouncedInput, setDebouncedInput] = useState('');
useEffect(() => {
const timer = setTimeout(() => setDebouncedInput(input), 500); // 500ms
debounce
return () => clearTimeout(timer); // Cleanup timeout on each change
}, [input]);
return (
<div>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<p>Debounced Value: {debouncedInput}</p>
</div>
Key Point: Debouncing input in React reduces unnecessary calls by delaying execution until
typing has paused, improving performance and user experience.
Approaches:
Local Storage: Save data with localStorage , which persists even after a browser is
closed.
Session Storage: Use sessionStorage for data that should persist only during the
session.
javascript
function PersistentComponent() {
const [name, setName] = useState(() => localStorage.getItem('name') ||
'');
useEffect(() => {
localStorage.setItem('name', name); // Update localStorage whenever
name changes
}, [name]);
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
Key Point: Use localStorage or sessionStorage in combination with React’s state and
useEffect to persist data across user sessions.
Usage in React:
Example:
javascript
function ParentComponent() {
const name = "Alice";
return <ChildComponent name={name} />;
}
Key Point: Shallow comparison in React enables efficient re-rendering by comparing reference
equality rather than deeply nested values, optimizing component updates.
Approaches:
Render Props: Share functionality across components using props to control what is
rendered.
javascript
function useLogging(componentName) {
useEffect(() => {
console.log(`${componentName} mounted`);
return () => console.log(`${componentName} unmounted`);
}, [componentName]);
}
function MyComponent() {
useLogging('MyComponent');
return <div>Component Content</div>;
}
Key Point: Cross-cutting concerns in React can be managed with HOCs, render props, and
custom hooks, allowing consistent functionality across the app.
Key Optimizations:
Use key properties in lists only if the order doesn’t change, ensuring stability.
Example:
javascript
function ParentComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(count + 1), [count]);
return (
<div>
<p>Count: {count}</p>
<Button handleClick={increment} />
</div>
);
}
76. How Would You Build a Hook That Mimics a Lifecycle Method?
Definition: React’s useEffect hook can be customized to mimic lifecycle methods from
class components.
Examples:
javascript
function useComponentDidMount(callback) {
useEffect(() => {
callback(); // Only runs once on mount
}, []);
}
function MyComponent() {
useComponentDidMount(() => {
console.log("Component Mounted");
});
return <div>My Component</div>;
}
Key Point: Custom hooks can encapsulate lifecycle-like behavior in React’s functional
components using the useEffect hook with specific dependency arrays.
Steps:
Tree Comparison: React compares the old and new virtual DOM trees node by node.
Types of Changes:
Element Type: If elements differ, React destroys the old element and creates a
new one.
Keys for Lists: Keys help identify which items have changed, added, or removed,
minimizing re-rendering in lists.
Optimization: By only updating the specific nodes that have changed, React avoids
unnecessary DOM updates, which improves performance.
Key Point: React’s diffing algorithm enables efficient updates by performing minimal
operations on the DOM, focusing only on nodes that changed.
78. How Would You Create a Global State Management Solution Using
Context and Hooks?
Context API and Custom Hooks:
The Context API allows you to create a global store that provides data and methods
to any component.
A custom hook can encapsulate the logic of accessing and updating this context.
Example:
javascript
return (
<GlobalContext.Provider value={{ globalState, toggleTheme }}>
{children}
</GlobalContext.Provider>
);
}
Usage:
javascript
function MyComponent() {
const { globalState, toggleTheme } = useGlobalContext();
return (
<div>
<p>Current Theme: {globalState.theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
Key Point: Combining Context with custom hooks creates a scalable global state management
solution in React without needing external libraries like Redux.
Race Conditions: Multiple async calls within useEffect may overlap, especially in
cases of rapid state changes or re-rendering.
Solutions:
javascript
useEffect(() => {
const controller = new AbortController();
fetchData(controller.signal);
return () => controller.abort(); // Cancel request on cleanup
}, [dependency]);
Key Point: To handle useEffect limitations, ensure proper dependency management, cancel
async operations, and use cleanup functions to prevent unexpected side effects.
Flagging State: Track each request with a unique identifier, canceling outdated
requests by comparing identifiers.
javascript
useEffect(() => {
const controller = new AbortController();
async function fetchData() {
try {
const response = await fetch(`https://api.example.com/data?
q=${query}`, {
signal: controller.signal
});
const result = await response.json();
setData(result);
} catch (error) {
if (error.name !== 'AbortError') console.error("Fetch error:",
error);
}
}
fetchData();
return () => controller.abort();
}, [query]);
How It Works:
When an event is triggered, React’s synthetic event system uses a single root-level
event listener.
The event is captured and dispatched down the virtual DOM tree, mimicking native
bubbling and capturing.
React creates synthetic events that normalize events across browsers, simplifying
event handling.
Benefits:
Reduced memory usage since listeners are not added to every element.
Key Point: React’s event delegation via a root listener optimizes performance by minimizing
event listeners and ensuring consistency across browsers.
Optimization Techniques:
Debouncing: Wait until the event has stopped firing for a specified time before
updating the component.
useRef for Static Values: Use useRef to store values without causing re-renders.
React.memo: Use React.memo to prevent re-renders when props have not changed.
javascript
function ThrottledMouseTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
Key Point: Handle high-frequency updates using throttling, debouncing, useRef , and
React.memo to minimize unnecessary renders and improve performance.
Key Implications:
Concurrency and Interruptible Rendering: Fiber allows React to break work into
units, pausing and resuming rendering as needed, enhancing responsiveness in
complex UIs.
Prioritization: With Fiber, updates are prioritized, allowing high-priority updates (like
user interactions) to be rendered before less critical ones.
Error Boundaries: Fiber introduced error boundaries, making it easier to catch and
handle errors within the component tree.
Impact on Developers:
More control over rendering behavior, especially for animations, large data sets, and
complex UIs.
Improved user experience by keeping the interface responsive even during heavy
computations.
Key Point: React Fiber brought improvements in concurrency, prioritization, and error
handling, making React apps more responsive and adaptable for complex scenarios.
Implementation:
Use useEffect to set a timer that updates the debounced value only when the
delay has passed.
javascript
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer); // Clear timer on change
}, [value, delay]);
return debouncedValue;
}
function DebouncedInput() {
const [input, setInput] = useState('');
const debouncedInput = useDebounce(input, 500); // 500ms delay
return (
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type here..."
/>
);
}
Key Point: A custom debounce hook can be easily created using useEffect to delay state
updates, useful for optimizing high-frequency updates.
Common Structure:
State Management: Use Context or a state management library (like Redux) for
global state, while keeping local state within components where possible.
Hooks and Utilities: Place shared hooks and utility functions in separate folders,
ensuring easy reuse and consistency across teams.
perl
src/
├── components/ # Reusable components (Button, Modal)
├── features/ # Feature-specific folders
│ ├── auth/
│ ├── user/
│ └── dashboard/
├── hooks/ # Custom hooks
├── services/ # API services, etc.
└── state/ # Global state management setup
Team Collaboration:
Clear Boundaries: Assign teams to specific features and enforce clear APIs and
contracts between modules.
Key Point: Structuring a large-scale React app involves feature-based organization, shared
component libraries, consistent documentation, and well-defined module boundaries to
enable efficient collaboration across teams.
How It Works:
Time Slicing: React splits rendering work into chunks and spreads them over
multiple frames to keep the main thread available.
Suspense for Data Fetching: Allows React to wait for asynchronous operations to
complete, displaying a fallback UI in the meantime.
Benefits:
Enhanced control over priority in the rendering process, with high-priority updates
rendered first.
Key Point: Concurrent Mode enables asynchronous, priority-based rendering, allowing React
to provide a more responsive and smoother experience.
Virtual DOM: React uses the Virtual DOM to minimize actual DOM updates, reducing
memory usage as only necessary changes are made to the DOM.
State and Context: React stores component state in memory, but unused
components can be garbage-collected once unmounted.
Optimization Techniques:
Key Point: React optimizes memory by managing DOM updates efficiently and using
techniques like garbage collection and proper cleanup in hooks.
How It Works:
Static Analysis: During the bundling process (e.g., using Webpack or Rollup), the
compiler analyzes import statements to determine which code is actually used.
Dead Code Elimination: Unused functions or modules are removed from the final
build.
Requirements:
Key Point: Tree-shaking reduces bundle size by removing unused code through static analysis,
resulting in faster loading and optimized React applications.
Immutable State Updates: Use spread operators or utilities like immer to create
updated state objects without mutating the original.
useReducer for Complex State: When managing deep or complex state structures,
Memoization: Use React.memo for components and useMemo for derived state
values to avoid unnecessary calculations.
javascript
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { nested: { field1: '',
field2: '' } });
return (
<input
onChange={(e) => dispatch({ type: 'updateNested', field: 'field1',
value: e.target.value })}
value={state.nested.field1}
/>
);
}
Key Point: Efficiently manage deep state updates by using immutability, useReducer ,
memoization, and component splitting to optimize performance.
How It Works:
Separate DOM Node: createPortal renders children into a specified DOM node
rather than the parent’s DOM hierarchy.
Portal Context: Even though a portal’s DOM node is outside the parent, it retains
access to React’s context and props from its logical parent component.
Example:
javascript
Benefits:
Portals simplify accessibility by allowing elements like modals to appear at the top of
the DOM while retaining React context.
Key Point: createPortal renders components into a specified DOM node outside of the
parent hierarchy, while maintaining access to the React context, making it ideal for elements
that need different styling or positioning.
Callback Functions: Pass down functions through props to handle updates at the
top level and allow children to update the parent state, reducing the need to pass
props down deeply.
javascript
function ParentComponent() {
const [value, setValue] = useState('');
Key Point: Avoid deep prop drilling by lifting state, using callback functions, and refactoring
the component tree, which reduces complexity and improves maintainability.
Use Cases:
Adding Props Dynamically: When you want to modify the props of a child
component, especially in a component that is part of a reusable or generic list.
Example:
javascript
// Usage:
<ParentComponent>
<ChildComponent />
</ParentComponent>
Key Point: React.cloneElement() allows you to clone and modify children elements,
enabling dynamic customization of components while maintaining their structure.
When to Use: SSR is beneficial for SEO, faster initial page load, and sharing dynamic
content.
Hydration: The process of making the static HTML content interactive by attaching
React’s event listeners and state to it.
When to Use: Hydration is necessary when SSR is used, as React needs to "take
over" the static HTML rendered by the server and enable interactivity.
Differences:
SSR is used to initially render the HTML on the server for faster page loads and SEO.
Hydration is used on the client to make SSR content interactive by attaching React’s
state and event listeners.
Key Point: SSR generates HTML on the server for performance and SEO, while hydration
enables React to take control of the page on the client-side.
React Suspense for Data Fetching: On the server, use Suspense for server-side data
fetching. You can use it with libraries like React-Query or Relay to handle async
operations and wait for data to be available before rendering the page.
Hydration on Client: Once the server-rendered page is hydrated on the client, React
will finish any remaining async work or data fetching, updating the UI as necessary.
Fallback Handling: Provide appropriate fallback UI both on the server side (during
SSR) and client-side (during hydration).
Key Point: In SSR, Suspense helps delay rendering until data is ready, but requires careful
synchronization between server rendering and client hydration.
95. What Are Concurrent Hooks, and How Do They Impact React
Performance?
Definition: Concurrent Hooks are designed to work with React's Concurrent Mode,
allowing React to manage updates asynchronously and prioritize them based on their
importance.
useTransition: Helps manage tasks with lower priority (e.g., transitions between
views or animations) and gives you control over the start and finish of the transition.
Improved Responsiveness: These hooks help React decide when to update the UI,
allowing higher-priority updates (like user input) to be processed first, without
blocking the UI.
Reduced Jank: By prioritizing critical tasks and deferring less critical ones, they
improve the performance of the application, especially during heavy computations
or complex UI updates.
Example of useTransition :
javascript
function MyComponent() {
const [isPending, startTransition] = useTransition();
return (
<div>
<input value={input} onChange={handleChange} />
{isPending ? <span>Loading...</span> : <div>{input}</div>}
</div>
);
}
Key Point: Concurrent hooks allow React to manage updates asynchronously, improve
responsiveness, and optimize performance by deferring less critical tasks when needed.
Prevention Techniques:
Use useEffect Cleanup: Always clean up side effects, such as API calls,
subscriptions, or timers, within the useEffect cleanup function.
javascript
useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(timer); // Cleanup on unmount
}, []);
javascript
useEffect(() => {
const handleResize = () => console.log('Window resized');
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
javascript
useEffect(() => {
let isMounted = true;
fetchData().then(data => {
if (isMounted) {
setData(data);
}
});
return () => { isMounted = false; }; // Cancel async operations
}, []);
Key Point: Ensure proper cleanup in useEffect , cancel async operations, and remove event
listeners to avoid memory leaks in React.
Props Customization: Allow customization of components via props so that they can
be highly dynamic and flexible. For example, provide slots or children elements,
Use Context for Global State: For managing shared states or themes, use Context
API or hooks.
TypeScript: Use TypeScript for type safety to enforce the expected structure of
props and reduce runtime errors.
javascript
Key Point: Build dynamic components using a modular structure, flexible props, dynamic
imports, and shared state management to create a robust component library.
98. What Strategies Would You Use to Implement Dark Mode Across a
React App?
Approaches:
CSS Variables: Use CSS variables for colors that can be easily changed based on the
theme (dark or light).
css
:root {
--background-color: white;
--text-color: black;
}
body.dark-mode {
State Management for Theme: Use useState or Context API to manage and toggle
the theme across the application.
javascript
return (
<div className={isDarkMode ? 'dark-mode' : ''}>
<button onClick={toggleTheme}>Toggle Dark Mode</button>
</div>
);
javascript
useEffect(() => {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) setIsDarkMode(savedTheme === 'dark');
}, []);
useEffect(() => {
localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
}, [isDarkMode]);
Key Point: Use CSS variables, state management, and persistent storage like localStorage to
implement a dynamic and persistent dark mode feature.
99. How Can You Prevent Frequent API Calls on Input Change in
React?
Solutions:
Debouncing: Implement debouncing to delay the API call until the user stops typing
for a specified period.
javascript
function SearchComponent() {
const [query, setQuery] = useState('');
const [debouncedQuery] = useDebounce(query, 500); // 500ms delay
useEffect(() => {
if (debouncedQuery) {
fetchAPI(debouncedQuery); // Call API with debounced query
}
}, [debouncedQuery]);
return (
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
}
Throttling: Implement throttling to limit the rate at which API calls are made.
Batching: Combine multiple user inputs into a single API request if possible.
Key Point: Debounce or throttle input events to reduce frequent API calls, improving both
performance and server load.
Optimization Strategies:
javascript
Web Workers: Offload data processing to Web Workers to keep the main thread
free for UI updates.
Lazy Loading: Load data in chunks or pages to avoid overwhelming the UI.
Efficient State Management: Use useReducer for better control over complex state
updates, and avoid storing large data structures directly in state.
Key Point: Optimize the handling of real-time data by using techniques like virtualization,
memoization, web workers, and efficient state management.