ReactJS is an open-source JavaScript library used to build fast and interactive user interfaces with reusable components, focusing mainly on the view layer.
- Uses component-based architecture for reusable UI.
- Efficiently updates UI with dynamic data.
- Works well with state management for complex logic.
- Advanced topics include performance optimization SSR concurrent rendering and hooks.
- Important for cracking mid to senior-level React interviews.
Before proceeding to learn ReactJS Interview Questions and Answers – Advance Level, you can first go through complete ReactJS Tutorial, ReactJS Interview Questions and Answers – Beginner Level.
1. What are custom hooks in React?
Custom hooks are JavaScript functions that start with the prefix use and leverage React’s built-in hooks (e.g., useState, useEffect) to encapsulate reusable logic. They promote the DRY (Don’t Repeat Yourself) principle, allowing developers to extract complex logic from components and reuse it across the application. Custom hooks simplify code, improve maintainability, and enhance testability by isolating logic from UI.
Common Custom Hooks:
- useFetch: Manages API requests, handling loading and error states.
- useLocalStorage: Persists data in localStorage across sessions.
- useDebounce: Delays function execution for scenarios like search inputs.
- usePrevious: Tracks the previous value of a state or prop.
- useToggle: Toggles a boolean state for UI elements like modals or switches.
Example (useFetch):
import { useState, useEffect } from 'react';
// Example custom hook: useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, {
signal: controller.signal,
});
if (!response.ok) {
throw new Error(`HTTP error! ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
if (err.name !== 'AbortError') {
setError(err);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
- Custom hooks must follow the naming convention (use*) to adhere to React’s rules.
- They can call other hooks but must be used at the top level of components or other hooks.
- They improve code reusability and make components cleaner by separating logic from UI.
2. How to optimize a React code?
Optimizing React code enhances application performance, reduces load times, and improves user experience. Advanced optimization techniques focus on minimizing re-renders, reducing bundle size, and improving rendering efficiency.
Optimization Techniques:
- Bind Functions in Constructor (Class Components): Avoid binding event handlers in the render method to prevent creating new functions on every render.
class MyComponent extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { console.log('Clicked'); } render() { return <button onClick={this.handleClick}>Click</button>; } } - Use React Fragments: Avoid unnecessary wrapper <div> tags to reduce DOM bloat.
return ( <> <h1>Title</h1> <p>Content</p> </> ); - Lazy Loading with
React.lazy: Load components only when needed to reduce initial bundle size.const LazyComponent = React.lazy(() => import('./LazyComponent')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </Suspense> ); } - Avoid Inline Attributes/Functions: Inline functions in JSX (e.g., onClick={() => doSomething()}) create new references on every render, causing child components to re-render unnecessarily. Use memoized callbacks with useCallback.
- Use React.memo: Prevent functional components from re-rendering if props haven’t changed.
const MyComponent = React.memo(({ data }) => <div>{data}</div>); - Optimize with useMemo and useCallback: Cache expensive computations or functions to avoid recalculation.
- Code Splitting: Split code into smaller chunks using dynamic imports or tools like Webpack.
- Production Builds: Use NODE_ENV=production to enable minification and optimizations.
Points:
- Profile performance with React Developer Tools to identify bottlenecks.
- Optimize images and assets to reduce load times.
- Consider SSR or static site generation with Next.js for faster initial renders.
3. What is the difference between useRef and createRef in React?
Both useRef and createRef create mutable references in React, but they differ in their usage, behavior, and context.
| useRef | createRef |
|---|---|
| Hook used in React | Function used in React |
| Used in functional components | Used in class components |
| Persists the same ref object across re-renders | Creates a new ref object on every render |
| Returns an object with a current property | Returns an object with a current property |
| Used for DOM references instance variables and storing previous values | Mainly used for DOM references in class components |
| Syntax: const ref = useRef(null) | Syntax: this.ref = React.createRef() |
Example (useRef):
import { useRef, useEffect } from 'react';
function InputFocus() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
}Example (createRef):
class InputFocus extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <input ref={this.inputRef} />;
}
}- useRef is preferred in modern React for functional components.
- createRef in class components can cause issues if not managed carefully, as it creates a new ref on each render.
- useRef can store mutable values without triggering re-renders, unlike state.
4. What is React Redux?
React Redux is the official React binding for Redux, a state management library that centralizes application state in a single store. It simplifies passing state between components, eliminating the need for prop drilling in large applications. Redux ensures predictable state updates through a unidirectional data flow, making it ideal for complex apps with shared state.
- Store: A single source of truth for the application state.
- Actions: Objects that describe state changes.
- Reducers: Pure functions that update the state based on actions.
Example:
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Slice
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment: (state) => {
state.count += 1;
},
},
});
const { increment } = counterSlice.actions;
// Store
const store = configureStore({
reducer: counterSlice.reducer,
});
// Component
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
</div>
);
}
// App
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}- React Redux connects React components to the Redux store using hooks like useSelector and useDispatch.
- It’s suited for large-scale apps with complex state requirements.
- Alternatives include Context API or Zustand for simpler state management.
5. What are the benefits of using React Redux?
React Redux offers several advantages for managing state in React applications, particularly in large or complex projects.
Benefits:
- Centralized State Management: A single store holds all application state, making it easier to manage and access.
- Performance Optimization: Redux prevents unnecessary re-renders by updating only components subscribed to relevant state changes.
- Debugging: Tools like Redux DevTools enable time-travel debugging, action replay, and state inspection.
- Persistent State: State can be saved to localStorage or a database for persistence across sessions.
- Predictable Updates: Reducers are pure functions, ensuring consistent state changes.
- Scalability: Redux’s structure supports growing applications with complex state interactions.
Points:
- Use Redux for apps with global state shared across many components.
- Combine with middleware like Redux Thunk for asynchronous operations.
- Evaluate simpler alternatives like Context API for smaller apps to avoid overhead.
6. Explain the core components of React Redux.
React Redux relies on four core concepts that define how data flows through a Redux-powered React application.
Core Components:
- Redux Store: A single JavaScript object that holds the entire application state. Created using createStore from Redux.
import { createStore } from 'redux'; const store = createStore(reducer); - Action Creators: Functions that return action objects, describing what should happen.
const increment = () => ({ type: 'INCREMENT' }); - Actions: Plain objects with a
typeproperty (and optional payload) that trigger state changes.{ type: 'INCREMENT', payload: 1 } - Reducers: Pure functions that take the current state and an action, returning a new state.
const reducer = (state = { count: 0 }, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; default: return state; } };
- The store dispatches actions, which reducers process to update the state.
- Use Provider from react-redux to make the store available to components.
- Actions are dispatched using useDispatch or connect in React Redux.
7. How can we combine multiple reducers in React?
In Redux, large applications often require multiple reducers to manage different parts of the state. The combineReducers function from Redux merges these reducers into a single root reducer, which is then passed to the store.
Syntax:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
reducer1: reducer1,
reducer2: reducer2,
});Example:
import { createStore, combineReducers } from 'redux';
// Books Reducer
const booksReducer = (state = [], action) => {
switch (action.type) {
case 'ADD_BOOK':
return [...state, action.payload];
default:
return state;
}
};
// Active Book Reducer
const activeBookReducer = (state = null, action) => {
switch (action.type) {
case 'SELECT_BOOK':
return action.payload;
default:
return state;
}
};
// Combine Reducers
const rootReducer = combineReducers({
books: booksReducer,
activeBook: activeBookReducer,
});
// Create Store
const store = createStore(rootReducer);- combineReducers creates a state object where each key corresponds to a reducer’s state slice.
- Each reducer manages its own state independently, promoting modularity.
- Use with useSelector to access specific state slices in components.
8. What is Context API?
The Context API is a React feature for sharing global state across a component tree without prop drilling. It’s lightweight, built into React, and ideal for managing data like themes, authentication, or locale settings. Context consists of a Provider to supply data and a Consumer (or useContext hook) to access it.
Syntax:
const MyContext = React.createContext(defaultValue);Example:
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Child />
</ThemeContext.Provider>
);
}
function Child() {
const theme = useContext(ThemeContext);
return <div>Theme: {theme}</div>;
}- Use Context for global state that doesn’t change frequently.
- Avoid overuse, as it can make components less reusable.
- For complex state, consider Redux or Zustand over Context.
9. Explain Provider and Consumer in Context API?
The Context API uses two key components to manage data flow: Provider and Consumer.
- Provider: A component that wraps part of the application and supplies the context value to its descendants. It’s typically placed high in the component tree.
- Consumer: A component (or useContext hook) that accesses the context value provided by the nearest Provider. It subscribes to changes in the context value.
Example:
import { createContext, useContext } from 'react';
const UserContext = createContext(null);
function App() {
const user = { name: 'John' };
return (
<UserContext.Provider value={user}>
<Child />
</UserContext.Provider>
);
}
function Child() {
const user = useContext(UserContext);
return <div>User: {user.name}</div>;
}- A Provider can override the default context value for its subtree.
- Multiple Providers can be nested, with children accessing the nearest one.
- Use useContext in functional components for simpler consumption.
10. Explain CORS in React with Axios.
Cross-Origin Resource Sharing (CORS) is a security mechanism that allows or restricts requests from a different domain than the server’s. In React, CORS issues arise when the frontend (e.g., running on localhost:3000) makes requests to a backend on a different domain (e.g., api.example.com). Axios, a popular HTTP client, can be configured to handle CORS-compliant requests.
Handling CORS:
- Backend Configuration: The server must include CORS headers like Access-Control-Allow-Origin to permit requests from the frontend’s domain.
- Frontend with Axios: Ensure requests include proper headers and handle CORS errors gracefully.
Example (Axios with CORS):
import axios from 'axios';
function fetchData() {
axios.get('https://api.example.com/data', {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // If cookies or auth are needed
})
.then(response => console.log(response.data))
.catch(error => console.error('CORS error:', error));
}- CORS is a server-side concern; the frontend can only handle errors, not resolve CORS issues.
- Use a proxy in development (e.g., in package.json: "proxy": "https://api.example.com") to bypass CORS.
- Libraries like fetch can also handle CORS, but Axios simplifies configuration.
11. What is Axios and how to use it in React?
Axios is a promise-based HTTP client for making asynchronous requests to REST APIs. It’s widely used in React for CRUD operations due to its simplicity, support for the Promise API, and features like request cancellation and interceptors.
Installation:
npm install axios
Example:
import { useState, useEffect } from 'react';
import axios from 'axios';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
axios.get('https://api.example.com/data')
.then(response => {
setData(response.data);
setLoading(false);
})
.catch(error => console.error('Error:', error));
}, []);
if (loading) return <div>Loading...</div>;
return <div>Data: {data.name}</div>;
}- Axios supports features like request timeouts, interceptors, and automatic JSON parsing.
- Use interceptors for global error handling or adding auth headers.
- Alternatives include fetch, but Axios provides a more robust API.
12. Write a program to create a counter with increment and decrement?
This program demonstrates a simple counter using the useState hook to manage state and event handlers for incrementing and decrementing the count. The UI updates automatically when the state changes.
Example:
import React, { useState } from 'react';
function Counter() {
const [counter, setCounter] = useState(0);
const handleIncrement = () => {
setCounter(counter + 1);
};
const handleDecrement = () => {
setCounter(counter - 1);
};
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h2>React Counter</h2>
<div style={{ fontSize: '24px', margin: '20px' }}>{counter}</div>
<div>
<button
onClick={handleIncrement}
style={{ margin: '5px', padding: '10px 20px' }}
>
Increment
</button>
<button
onClick={handleDecrement}
style={{ margin: '5px', padding: '10px 20px' }}
>
Decrement
</button>
</div>
</div>
);
}
export default Counter;How It Works:
- useState initializes counter to 0 and provides setCounter to update it.
- handleIncrement increases the counter by calling setCounter(counter + 1).
- handleDecrement decreases the counter by calling setCounter(counter - 1).
- The UI displays the current counter value and updates on button clicks.
Points:
- Use descriptive handler names (e.g., handleIncrement) for clarity.
- Inline styles are used here for simplicity; prefer CSS Modules or styled-components in production.
- Ensure state updates are immutable to avoid bugs.
13. Explain why and how to update state of components using callback?
In React, state updates with setState (in class components) or useState setters are asynchronous to optimize performance. Using a callback-based approach ensures updates are based on the previous state, preventing bugs when multiple updates occur in quick succession.
Why Use Callbacks:
- Avoid Stale State: Since setState is async, relying on the current state value can lead to outdated results.
- Batched Updates: React batches state updates for efficiency, and callbacks ensure correct sequencing.
- Predictable Updates: Callbacks make state transitions explicit and reliable.
Example (Class Component):
class Counter extends React.Component {
state = { count: 0 };
handleClick = () => {
this.setState(prevState => ({
count: prevState.count + 1,
}));
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}Example (Functional Component):
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(prevCount => prevCount + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}- Use the callback form (e.g., prevState => ...) when the new state depends on the previous state.
- Callbacks are essential in scenarios like rapid user interactions or async operations.
- Functional updates improve code reliability and reduce bugs.
14. What is React Material UI?
Material UI is a popular React UI framework that provides pre-built components following Google’s Material Design guidelines. It offers customizable, accessible, and responsive components for building modern React applications. Material UI is widely used for its ease of integration and compatibility with frameworks like React, Angular, and Vue.
Example:
import { Button, TextField } from '@mui/material';
function Form() {
return (
<div>
<TextField label="Name" variant="outlined" />
<Button variant="contained" color="primary">
Submit
</Button>
</div>
);
}- Install with npm install @mui/material @emotion/react @emotion/styled.
- Components are highly customizable via props or theme overrides.
- Supports TypeScript and server-side rendering for production-ready apps.
15. What is Flux architecture in Redux?
Flux is an application architecture popularized by Facebook for managing data flow in React applications. It emphasizes unidirectional data flow, which Redux builds upon. Flux consists of four parts: Dispatcher, Stores, Actions, and Views (React components).
Flux in Redux:
- Store: Equivalent to Redux’s store, holding the application state.
- Actions: Same as Redux actions, triggering state changes.
- Dispatcher: Handled internally by Redux, dispatching actions to reducers.
- Reducers: Replace Flux’s store logic, updating state based on actions.
Points:
- Redux is a refined implementation of Flux with a single store and pure reducers.
- Unidirectional data flow ensures predictable state management.
- Use Redux Toolkit to simplify Flux-like patterns in modern Redux.
16. Explain the useMemo hook in React?
The useMemo hook memoizes expensive computations in functional components, returning a cached value unless its dependencies change. It optimizes performance by preventing redundant calculations during re-renders.
Syntax:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);Example:
import { useMemo, useState } from 'react';
function ExpensiveComponent({ numbers }) {
const [count, setCount] = useState(0);
const sum = useMemo(() => {
console.log('Calculating sum...');
return numbers.reduce((acc, num) => acc + num, 0);
}, [numbers]);
return (
<div>
<p>Sum: {sum}</p>
<button onClick={() => setCount(count + 1)}>Re-render ({count})</button>
</div>
);
}- Use useMemo for computationally heavy operations or to stabilize object references.
- Include all dependencies used in the computation to avoid stale values.
- Overusing useMemo can increase memory usage; apply it judiciously.
17. Does React’s useState Hook update immediately?
The useState hook’s setter function does not update state immediately. React batches state updates for performance and processes them asynchronously during the next render cycle. This queuing mechanism ensures React knows which state corresponds to which component, but it can lead to stale state if not handled properly.
Example:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
console.log(count); // Logs old value due to async update
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
Solution: Use a functional update to ensure updates are based on the latest state:
setCount(prevCount => prevCount + 1);- State updates are queued and applied during re-rendering.
- Use functional updates or useEffect to handle side effects after state changes.
- React’s batching improves performance but requires careful state management.
18. When to use useCallback, useMemo, and useEffect?
These hooks serve distinct purposes in optimizing and managing functional components.
- useEffect: Handles side effects like data fetching, subscriptions, or DOM updates. Replaces lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount).
useEffect(() => { fetchData(); return () => cleanup(); }, [dependency]); - useCallback: useCallback is used to memoize functions, mainly to optimize performance when passing callbacks to child components.
const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]); - useMemo: The useMemo hook is used to memoize expensive computations in functional components. It returns a cached value and only recalculates it when its dependencies change, helping improve performance.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
When to Use:
- useEffect: For side effects triggered by state/prop changes or component lifecycle events.
- useCallback: When passing functions to React.memo-wrapped components to prevent re-renders.
- useMemo: For caching results of heavy computations or stabilizing object references.
Points:
- Use these hooks sparingly to avoid over-optimization.
- Ensure correct dependency arrays to prevent bugs.
- Profile performance to determine necessity.
19. Explain the types of routers in React?
React Router provides three types of routers for handling navigation in React applications, each suited for different use cases.
Types of Routers:
- BrowserRouter: Uses HTML5 history API (pushState, replaceState, popState) to manage URLs, providing clean URLs (e.g., /about). Ideal for web applications with server support.
import { BrowserRouter } from 'react-router-dom'; - HashRouter: Uses the hash portion of the URL (e.g., /#about) for routing. Suitable for static sites or environments without server-side routing.
import { HashRouter } from 'react-router-dom'; - MemoryRouter: Stores URL history in memory, not in the browser. Useful for testing or non-browser environments like React Native.
import { MemoryRouter } from 'react-router-dom';
- BrowserRouter is the most common for modern web apps.
- HashRouter is simpler for static hosting but less SEO-friendly.
- MemoryRouter is rare, primarily for non-browser contexts.
20. What is StrictMode in React?
StrictMode is a React component that wraps parts of an application to highlight potential issues during development. It doesn’t render any UI but enables additional checks and warnings to improve code quality.
Features:
- Identifies deprecated APIs and unsafe lifecycle methods.
- Warns about side effects in useEffect or useState.
- Detects unexpected side effects by double-invoking certain functions in development.
Example:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);- Only active in development mode; no impact in production.
- Helps catch bugs early, especially with React 18’s concurrent features.
- Wrap only specific parts of the app if needed to isolate checks.
21. What is Conditional Rendering in React?
Conditional rendering in React involves dynamically displaying components or elements based on conditions like state, props, or API responses. It’s essential for creating responsive UIs tailored to user interactions or data.
Use Cases:
- Show/hide elements based on authentication status.
- Display different layouts for user roles.
- Render loading spinners during data fetching.
- Conditionally show UI based on API responses.
Example:
import { useState } from 'react';
function UserStatus() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
{isLoggedIn ? <h1>Welcome, User!</h1> : <h1>Please Log In</h1>}
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? 'Log Out' : 'Log In'}
</button>
</div>
);
} - Use ternary operators or logical && for concise rendering.
- Move complex logic outside JSX for readability.
- Avoid over-nesting conditions to maintain clarity.
22. What is React Router?
React Router is a library for managing navigation in React single-page applications (SPAs). It enables dynamic routing, allowing components to render based on the URL without full page reloads, providing a seamless user experience.
Example:
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link> | <Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}
export default App;How It Works:
- BrowserRouter wraps the app to enable routing.
- Link creates navigable links without page reloads.
- Routes and Route map URLs to components.
- React 18 uses createRoot for rendering, supporting concurrent features.
Points:
- Use
Routesinstead of Switch in React Router v6. - Supports nested routes, dynamic parameters, and programmatic navigation.
- Configure server for SPA routing to handle direct URL access.
23. What is the difference between React Hooks and Class Components?
React Hooks and class components offer different approaches to building React applications, with hooks being the modern standard.
Comparison Table:
| Feature | React Hooks | Class Components |
|---|---|---|
| State Management | useState for state | this.state and this.setState |
| Reusability | Custom hooks for shared logic | Inheritance or HOCs, more complex |
| this Keyword | No this; direct access to state/functions | Uses this for state and methods |
| Lifecycle Methods | useEffect for side effects | componentDidMount, componentDidUpdate, etc. |
| Performance | Better optimizations with hooks API | Less efficient, more boilerplate |
Example (Hooks):
import { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}Example (Class):
class Counter extends React.Component {
state = { count: 0 };
componentDidMount() {
document.title = `Count: ${this.state.count}`;
}
componentDidUpdate() {
document.title = `Count: ${this.state.count}`;
}
render() {
return (
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
{this.state.count}
</button>
);
}
}- Hooks reduce boilerplate and improve readability.
- Class components are still supported but less common in new code.
- Hooks enable functional components to handle state and side effects.
24. How is data passed between React components?
Data in React flows primarily through props, but other methods exist for complex scenarios.
Methods:
- Props (Parent to Child): Pass data via attributes to child components.
function Parent() {return <Child name="John" />;}function Child({ name }) {return <div>{name}</div>;} - Callback Functions (Child to Parent): Pass functions as props to update parent state.
function Parent() { const [data, setData] = useState(''); return <Child setData={setData} />; } function Child({ setData }) { return <button onClick={() => setData('Updated')}>Update</button>; } - Context API: Share global data without prop drilling.
- Redux/State Management: Centralize state for complex apps.
- Render Props: Pass components as props to share logic.
Points:
- Props are read-only; never mutate them directly.
- Use Context or Redux for deeply nested components.
- Choose the simplest method for your use case to avoid complexity.
25. What is Lazy Loading in React?
Lazy loading defers loading components until they’re needed, reducing initial bundle size and improving app performance. React provides React.lazy and Suspense for implementing lazy loading.
Example:
import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}- React.lazy works with dynamic imports for code splitting.
- Suspense displays a fallback UI during loading.
- Use with tools like Webpack for optimal bundle splitting.
26. Explain Redux and its components.
Redux is a state management library for predictable state updates. Its core components are:
- Store: Holds the entire application state in a single object.
- Actions: Plain objects describing state changes (e.g., { type: 'ADD', payload: 1 }).
- Reducers: Pure functions that update state based on actions.
Example:
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Slice
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
add: (state, action) => {
state.count += action.payload;
},
},
});
const { add } = counterSlice.actions;
// Store
const store = configureStore({
reducer: counterSlice.reducer,
});
// Component
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(add(1))}>
Add
</button>
</div>
);
}
// App
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}- Use Redux Toolkit to reduce boilerplate in modern Redux.
- Middleware like Redux Thunk enables async actions.
- Redux is overkill for small apps; consider Context API instead.
27. How is React Routing different from Conventional Routing?
React Router handles client-side routing for SPAs, while conventional routing typically involves server-side routing for multi-page applications.
Comparison Table:
| Feature | React Routing | Conventional Routing |
|---|---|---|
| Page Loading | No full reload; components render dynamically | Full page reload on navigation |
| SEO | Requires SSR or prerendering for SEO | Naturally SEO-friendly due to server rendering |
| Navigation | JavaScript-driven with Link/NavLink | Server-driven with <a> tags |
| Technology | Client-side via React Router | Server-side (e.g., Express, PHP) |
| URL Structure | Supports dynamic parameters (e.g., /user/:id) | Typically static URLs |
- React Router uses BrowserRouter for clean URLs or HashRouter for static sites.
- Configure servers to redirect SPA routes to index.html for direct access.
- Use Next.js for hybrid routing with SSR.
28. How to avoid binding in ReactJS?
In class components, event handlers require binding to ensure the correct this context. However, binding can be avoided to reduce boilerplate and improve performance.
Methods to Avoid Binding:
- Arrow Functions in Class Fields: Define methods as arrow functions to lexically bind
this.class MyComponent extends React.Component { handleClick = () => { console.log(this.state); }; render() { return <button onClick={this.handleClick}>Click</button>; } } - Arrow Functions in Render: Use inline arrow functions (but avoid for performance-critical components).
<button onClick={() => this.handleClick()}>Click</button> - Custom Hooks/HOCs: In functional components, hooks eliminate binding entirely.
function MyComponent() { const handleClick = () => { console.log('Clicked'); }; return <button onClick={handleClick}>Click</button>; }
- Arrow functions are the modern standard to avoid binding.
- Avoid inline functions in render for memoized components to prevent re-renders.
- Functional components with hooks make binding obsolete.
29. What are props in React?
Props (properties) are read-only data passed from a parent component to a child component to configure its behavior or appearance. They enable component reusability and dynamic rendering.
Example:
function Parent() {
return <Child name="Alice" age={25} />;
}
function Child({ name, age }) {
return <div>{name} is {age} years old</div>;
}- Props are immutable; child components should not modify them.
- Use default props or prop types for robustness.
- Props can include functions, objects, or any valid JavaScript value.
30. What is the use of CSS Modules in React?
CSS Modules scope styles locally to a component, preventing style conflicts in large applications. They generate unique class names at build time, ensuring styles apply only to the intended component.
Example:
/* styles.module.css */
.button {
background-color: blue;
color: white;
}import styles from './styles.module.css';
function Button() {
return <button className={styles.button}>Click</button>;
}- CSS Modules are enabled in Create React App by default with .module.css files.
- Use camelCase for class names in JavaScript (e.g., styles.myButton).
- Alternatives include styled-components or Tailwind CSS.