Web Development
React.js Questions
Comprehensive collection of the most frequently asked React JS interview questions covering fundamentals, hooks, routing, testing, and advanced concepts. Each answer is concise and interview-ready.
React Basics3
React is a JavaScript library by Facebook for building user interfaces using reusable components. Main features include: component-driven architecture, virtual DOM for optimized rendering, declarative programming, and strong community support. Components manage their own state, making applications predictable and easier to maintain.
JSX (JavaScript XML) is a syntax extension allowing HTML-like code in JavaScript. It gets compiled by Babel into React.createElement() calls. For example, <div>Hello</div> becomes React.createElement('div', null, 'Hello'). This makes component code more readable and maintainable.
React Fragments allow grouping multiple elements without adding extra DOM nodes. Use them when returning multiple elements from a component without wrapper elements. Syntax: <></> or <React.Fragment>. Useful for lists, tables, and keeping DOM structure clean.
React Core3
The Virtual DOM is an in-memory representation of the actual DOM. React compares the new Virtual DOM with the previous one through a process called reconciliation and updates only the parts that changed. This improves performance by reducing expensive direct DOM manipulations.
Reconciliation is React's process of updating the DOM to match the Virtual DOM. It compares new and previous Virtual DOM trees, determining minimum changes needed. This ensures optimal performance by avoiding unnecessary DOM manipulations and re-renders.
Re-rendering updates the UI when component state or props change. React recalculates JSX, compares with previous output using Virtual DOM, and updates only the differences in the real DOM. This keeps the UI synchronized with component state and props efficiently.
React Performance6
Virtual DOM works by creating a lightweight copy of the real DOM, diffing it with the previous version, and applying only necessary changes. Benefits: improved performance and predictable updates. Downsides: overhead from diffing algorithms and extra memory usage. In highly dynamic UIs, manual optimizations might perform better.
Pure Components re-render only when props or state change using shallow comparison. Class components extend React.PureComponent; functional components use React.memo(). They optimize performance by preventing unnecessary re-renders, but be cautious with complex objects as shallow comparison may miss changes.
Code splitting divides code into chunks loaded on demand, reducing initial load times. Achieve via dynamic import() or React.lazy() with Suspense. This improves performance for large applications by loading only necessary code when needed.
Optimize context by memoizing values with useMemo, splitting contexts for isolated state changes, and using selectors for component-specific data. Prevent unnecessary re-renders by reducing context consumers or extracting frequently-changing data into separate contexts.
Lazy loading loads components only when needed rather than at startup, improving initial load time. Use React.lazy() with dynamic import() and Suspense for fallback UI. This code-splitting technique is essential for large applications optimizing performance.
Use Web Workers for offloading computation, setTimeout/requestIdleCallback for deferring work, or useMemo/useCallback for optimization. Break tasks into smaller chunks and defer non-critical work. Suspense or async patterns can handle asynchronous computations gracefully.
React Concepts2
React Node is any unit renderable in React (elements, strings, numbers, null). React Element is an immutable object describing what to render, created via JSX or createElement(). React Component is a function or class returning React Elements, enabling reusable UI components.
One-way data flow means data moves parent-to-child via props. Child components call parent functions to change data, triggering re-renders. This unidirectional flow makes applications predictable and easier to debug, preventing circular dependencies and data inconsistencies.
React Lists1
The key prop uniquely identifies list elements, helping React optimize rendering. It allows React to maintain element identity during reordering or deletion. Without unique keys, React may re-render unnecessarily or display incorrect data. Always use unique identifiers, not array indices.
React Best Practices4
Using array indices as keys causes performance issues and bugs, especially with reordering or deletion. React loses track of element identity, leading to unnecessary re-renders and incorrect data display. Always use stable, unique identifiers like IDs instead of indices.
Direct state mutations prevent React from detecting changes, breaking reactivity. Immutability helps React determine when re-rendering is needed through reference comparison. Always use setState or hooks like useState to create new state objects, ensuring proper change detection and predictable behavior.
Common anti-patterns: directly mutating state, using componentWillMount for data fetching, overusing componentWillReceiveProps, array indices as keys, excessive inline functions, deeply nested state. Avoid these by following React best practices, using hooks, and proper state management.
Common pitfalls: ignoring loading/error states, memory leaks from uncleared subscriptions, improper lifecycle method usage, missing dependency arrays in useEffect. Always clean up subscriptions, manage states properly, and use modern hooks correctly to avoid these issues.
React State Management4
Props are immutable inputs passed from parent to child components for configuration. State is internal, mutable data managed within a component that can change over time. Props flow downward; state is local. Changes to state trigger re-renders, changes to props may trigger child re-renders.
Lifting state involves moving state from child components to their nearest common ancestor. This shares state between components without direct parent-child relationships, avoiding prop drilling. It simplifies shared data management and creates a single source of truth for multiple components.
The callback function format of setState receives previous state and props, ensuring state updates depend on current values. Use when new state depends on previous state. This avoids asynchronous update issues, guaranteeing accurate state reflects latest values.
setState triggers state update and component re-render. React may batch multiple setState calls into single update for performance. Updates are asynchronous; React schedules them to optimize rendering. Re-render recalculates Virtual DOM, updates real DOM with differences, and triggers child re-renders if needed.
React Components4
Class components extend React.Component, manage state via this.state, and use lifecycle methods. Functional components are simpler functions taking props and returning JSX. With hooks, functional components can manage state and lifecycle, making them the modern standard for most use cases.
Class components were necessary for state management and lifecycle methods. However, with hooks, functional components handle these features better. Use class components only for legacy code or specific error boundary use cases. Functional components with hooks are preferred for cleaner, more readable code.
Stateless components (presentational components) don't manage internal state; they receive data via props and render UI. They're typically functional components focused on displaying information. Benefits include simplicity, easier testing, and reusability. With hooks, the term is less relevant since functional components can have state.
Stateful components manage internal state using this.state (class) or useState (functional). They respond to user interactions and events, updating state to trigger re-renders. Essential for dynamic, interactive UIs. With hooks, most components are functional and stateful, blurring traditional distinctions.
React Architecture1
React Fiber is a complete rewrite of React's core algorithm improving performance and enabling features like async rendering, error boundaries, and incremental rendering. It breaks rendering into chunks, allowing React to pause, abort, or prioritize updates based on importance, resulting in smoother user experiences.
React Advanced6
Shadow DOM is a web standard encapsulating DOM parts, isolating them from global styles and scripts, used for reusable components. Virtual DOM is React's in-memory representation optimizing rendering by updating only necessary parts. Shadow DOM is browser-level; Virtual DOM is React-specific.
forwardRef allows passing refs through components to child elements, enabling direct DOM access from parent components. Use for accessing inputs, managing focus, or triggering imperative actions. It bypasses React's declarative model; use only when necessary for specific DOM operations.
Suspense handles asynchronous operations elegantly, displaying fallback content while waiting for resources. Use with React.lazy() for code splitting and dynamic imports. It enables cleaner handling of loading states without explicit loading state management.
Portals render children into DOM nodes outside parent hierarchy, useful for modals, tooltips, and dropdowns escaping parent overflow or z-index constraints. Use ReactDOM.createPortal(component, domNode) to render outside normal component tree while maintaining React event handling.
Concurrent Mode enables React to work on multiple tasks simultaneously without blocking the main thread. It prioritizes updates, providing smoother rendering for complex applications. This enables better responsiveness by pausing non-urgent work for high-priority user interactions.
React's priority system schedules updates based on importance. User interactions (clicks, input) receive higher priority than background updates. Concurrent Mode breaks large updates into chunks, allowing React to pause and resume work, ensuring responsive UI for time-sensitive interactions.
React Forms1
Controlled components manage form data through state with event handlers, making state the single source of truth. Uncontrolled components manage form state internally using refs. Controlled components offer better control and testability; uncontrolled components are simpler for basic use cases.
React APIs1
createElement creates new React elements by taking type, props, and children. cloneElement clones existing elements and optionally modifies props while preserving children. createElement is used for dynamic element creation; cloneElement for element manipulation without recreation.
React Type Checking2
PropTypes provides runtime type-checking for component props during development, ensuring correct data types. It helps catch errors early, improving code quality. However, modern React projects prefer TypeScript for compile-time type checking, which is more robust than PropTypes.
TypeScript is recommended for static type-checking, providing compile-time checks, autocompletion, and better tooling integration. PropTypes offer runtime checks during development but lack static analysis. For production applications, TypeScript is preferred; for smaller projects, PropTypes suffice.
React Hooks10
Hooks enable state and React features in functional components, eliminating class component complexity. They streamline code by reducing lifecycle method reliance, improve readability, and facilitate reusable stateful logic. Popular hooks: useState, useEffect, useContext, allowing modern, maintainable React code.
Hooks must be called at the top level of functions, not inside loops, conditions, or nested functions. They work only in React functional components or custom hooks. Following these rules ensures proper state management and lifecycle behavior. Eslint plugins help enforce these rules automatically.
useEffect runs asynchronously after DOM rendering, suitable for data fetching and subscriptions. useLayoutEffect runs synchronously after DOM updates but before painting, ideal for measuring elements or DOM-based UI alignment. useEffect is preferred; useLayoutEffect for specific DOM measurement needs.
The dependency array controls when useEffect runs: empty array = runs once after mount; with variables = runs when those change; omitted = runs after every render. Properly managing dependencies prevents bugs and unnecessary effect executions, optimizing performance.
useRef creates mutable references persisting across renders, enabling direct DOM access and storing values without triggering re-renders. Use for focusing inputs, managing timers, or storing mutable values. Refs bypass React's declarative model; use sparingly for specific imperative needs.
useCallback memoizes functions, preventing recreation on every render. Use when passing callbacks to optimized child components depending on reference equality. This avoids unnecessary child re-renders. Essential for performance optimization with React.memo or PureComponent children.
useMemo memoizes expensive calculations, recomputing only when dependencies change. Use for computationally intensive functions avoiding re-calculation every render. This optimizes performance for heavy computations. Avoid overusing; measure actual performance impact before applying.
useReducer manages complex state logic in functional components as an alternative to useState. Ideal for multiple state fields with constraints or when next state depends on previous. It accepts a reducer function and initial state, dispatching actions to update state.
useId generates unique IDs for elements, crucial for accessibility linking form inputs and labels. It creates IDs that remain consistent across renders and server-side rendering. Use for dynamic form elements or components rendering multiple times to ensure unique identifiers.
Create custom hooks as functions starting with 'use', utilizing built-in hooks like useState and useEffect, returning shared values or functions. Custom hooks reuse logic across components, keeping code clean and maintainable. They follow React hook rules and enable logic extraction from components.
React Error Handling1
Error boundaries catch JavaScript errors in child components, log them, and display fallback UI instead of crashing. They use componentDidCatch and getDerivedStateFromError methods. Note: they don't catch event handler errors or asynchronous code errors, requiring try-catch or Promise rejection handlers.
React SSR2
Hydration attaches event listeners and makes server-rendered HTML interactive on the client. After server-side rendering, React initializes dynamic behavior by attaching handlers. This enables fast initial page load (from server HTML) with full interactivity (from client-side React).
Server-side rendering (SSR) renders components on the server, sending fully rendered HTML to clients. Benefits: improved initial load time, better SEO, reduced time-to-interactive. Hydration makes server-rendered HTML interactive on the client.
React Development1
Strict Mode activates extra development checks detecting unsafe lifecycles, side effects, and unexpected state mutations. It warns about deprecated methods and enforces best practices without affecting production. Wrap components in <React.StrictMode> to identify potential issues early.
State Management2
Flux manages application state through unidirectional data flow: Actions → Dispatcher → Stores → Views. This pattern simplifies debugging and enhances maintainability through clear separation of concerns. It inspired Redux and other state management libraries.
Use React state for local component state, context for global state across components, and external managers (Redux, Zustand) for complex state requiring advanced features. Consider application complexity, team familiarity, and scalability needs when choosing.
React Patterns6
Context can cause unnecessary re-renders of consumers even if only part of context changes. Overusing context makes code harder to maintain and understand. For complex state management, consider Redux, Zustand, or other solutions. Use context sparingly for truly global state.
Prop drilling passes data through intermediate components not using it, from parent to deeply nested children. While acceptable for shallow hierarchies, it becomes problematic in deep component trees. Use context or state management libraries to avoid drilling multiple props through many layers.
Higher-order components (HOCs) are functions accepting a component and returning an enhanced version with added props or behavior. They facilitate logic reuse across components but can create wrapper hell. Hooks provide a cleaner alternative for most use cases.
Presentational components focus on appearance, rendering HTML and CSS based on props. Container components manage logic, state, and data fetching, passing data to presentational components. This separation improves code organization, testability, and reusability.
Render props involve passing a function as a prop that returns React elements, enabling code sharing between components. Functions receive component data as arguments. This technique facilitates logic reuse without HOCs but can reduce readability with deeply nested renders.
Composition builds complex components from smaller reusable ones rather than inheritance. Components accept children via props, combining them to create complex UIs. This approach is more flexible, maintainable, and aligns with React's component philosophy.
React Events2
Synthetic events wrap native DOM events, ensuring consistent behavior across browsers. React pools and reuses event objects for performance. They provide a unified API with methods like preventDefault() and stopPropagation(), simplifying cross-browser event handling.
Use useEffect to listen for window resize events, updating state when triggered. Store windowWidth in state; whenever window resizes, setState updates width and triggers re-render. Remember to clean up event listeners in the effect's cleanup function.
React Lifecycle1
Mounting: constructor (state init), componentDidMount (API calls). Updating: shouldComponentUpdate (prevent re-render), componentDidUpdate (side effects). Unmounting: componentWillUnmount (cleanup). Hooks (useEffect) replicate these in functional components more elegantly.
React Static Generation1
Static generation pre-renders HTML at build time rather than runtime. This approach delivers static content quickly, improving performance and SEO. Ideal for static sites with infrequent updates. Can be revalidated to ensure freshness without full rebuilds.
React Data Fetching1
Use useEffect hook to fetch data, managing loading and error states with useState. Fetch data inside effect, update state with results. Handle loading state UI and error states appropriately. Consider libraries like React Query for advanced data fetching and caching.
React Router14
React Router is a popular client-side routing library enabling navigation between components based on URL. It provides declarative routing with components like BrowserRouter, Routes, and Route, allowing single-page applications to manage navigation seamlessly.
React Router maps URL paths to components. Dynamic routing uses URL parameters like :id captured via useParams hook. This enables rendering components based on dynamic URL values, powering applications with variable content like user profiles or product pages.
Use <Outlet> to render child routes within parent layouts and useParams to access dynamic parameters. Nested routes create component hierarchies matching URL structure, enabling modular, organized routing architecture.
BrowserRouter uses HTML5 History API for clean URLs (no hash), requiring server-side routing configuration. HashRouter uses URL hash (#) for client-side routing without server setup. HashRouter suits static hosting; BrowserRouter works best with server-side routing support.
React Router is a complete routing solution managing UI and navigation. History library is lower-level, managing browser history stack only. React Router uses history internally but adds routing, component management, and declarative API.
v6 Router components: BrowserRouter (History API, clean URLs), HashRouter (URL hash, no server config), MemoryRouter (in-memory, non-browser), StaticRouter (server-side rendering). Each serves different use cases but provides consistent routing functionality.
push() adds new history entry, allowing back navigation to previous page. replace() replaces current entry, preventing back navigation to the replaced page. Use push for normal navigation; use replace for redirects or state changes not warranting back navigation.
Use useNavigate hook in v6 to get navigate function; call navigate('/path') for navigation. In v5, use useHistory hook with history.push('/path'). Programmatic navigation enables navigation triggered by events, logic, or timers rather than user clicks.
Create a PrivateRoute component checking authentication before rendering protected routes. If unauthenticated, redirect to login. Use Navigate component for redirection in v6. This pattern protects sensitive routes from unauthorized access.
Use useLocation hook to get current route, conditionally applying styles to active links. Compare location.pathname with route paths to highlight active navigation items. This provides visual feedback of current page location.
Create a catch-all route using path='*' at the end of Routes, rendering a NotFound component. This handles unmatched URLs, displaying a 404 error page. Place it last so specific routes match before the catch-all.
Use useSearchParams hook in v6 to access and manipulate query parameters. Call searchParams.get('paramName') to retrieve values. This enables handling optional parameters in URLs for filtering or pagination.
After successful authentication, use useNavigate to redirect to desired route like '/dashboard'. Store authentication status in state/context, checking it in PrivateRoute components to ensure proper redirection flow.
In v6, use the element prop with JSX: <Route path='/path' element={<Component prop='value' />} />. This allows passing props directly to route components without intermediaries.
React i18n7
Use internationalization libraries like react-i18next or react-intl. Set up translation files for different languages, configure the library with locale settings, and use hooks/components for translations. This enables multi-language support across applications.
react-intl is a library providing internationalization (i18n) support for React. It formats numbers, dates, strings, and handles translations. It integrates with JavaScript's Intl API for locale-specific data and translation management.
Features include formatted text with placeholders, number/currency/percentage formatting, date/time formatting by locale, plural and gender-aware translations. Provides both component-based and hook-based APIs for flexible implementation.
Component-based: use <FormattedMessage />, <FormattedNumber />, <FormattedDate />. Hook-based: use useIntl hook for imperative formatting. Choose components for templates, hooks for dynamic formatting in component logic.
Use <FormattedMessage id='key' defaultMessage='Hello {name}' values={{name: 'John'}} />. Placeholders like {name} get replaced with values from the values prop, enabling dynamic translations.
Use useIntl hook to access intl.locale showing current locale. Or pass locale prop to IntlProvider like <IntlProvider locale='en'>. This enables locale-specific formatting and conditional rendering based on language.
Use <FormattedDate value={date} year='numeric' month='long' day='2-digit' /> component or useIntl().formatDate() hook. Both provide locale-aware date formatting following local conventions.
React Testing14
Use Jest as the test runner and assertion library with React Testing Library for component testing. React Testing Library tests components from user perspective, simulating interactions. Jest provides mocking, assertions, and test execution.
Jest is a JavaScript testing framework providing test runner, assertions, and mocking. It integrates seamlessly with React and React Testing Library, running tests in isolated environments. Jest handles snapshots, code coverage, and parallel test execution.
React Testing Library provides utilities for testing React components like users would interact. Render components with render(), interact with fireEvent or userEvent, and assert with queries like getByText, getByRole. It encourages testing behavior over implementation.
Render component with render(), simulate interactions using fireEvent or userEvent, assert results with screen queries. Test behavior and output, not implementation details. Keep tests focused, readable, and maintainable.
Use waitFor from React Testing Library to wait for asynchronous operations. Alternatively, use findBy queries which implicitly wait. Handle promises, async/await, and API calls properly in tests for reliable async component testing.
Use jest.mock() to mock API modules, returning mock data. Mock fetch or axios as needed. This enables testing components with controlled data without actual network requests, speeding up tests and avoiding external dependencies.
Use renderHook from @testing-library/react to render hooks in isolation. Wrap state updates with act() to batch updates properly. Test hook return values and side effects, ensuring hooks behave correctly.
Use renderHook to render custom hooks in testing environment. Call hook functions with act(), test returned values and side effects. Custom hook tests ensure reusable logic works correctly across components.
Shallow Renderer tests components without rendering children, isolating components for unit testing. Use Enzyme's shallow() for component testing. Useful for testing component logic and props independently without complex dependency chains.
Snapshot Testing captures component output and compares future renders against it. Jest's toMatchSnapshot() saves and compares snapshots. Useful for regression testing UI but can produce brittle tests; use sparingly for stable components.
Wrap test components in context providers with specific values. Render components inside providers to simulate context usage. Test components with different context values to ensure proper behavior in various scenarios.
Use redux-mock-store to create mock stores with desired state. Wrap tested components in Provider with mock store. Test component rendering with different Redux states and action dispatches.
Shallow rendering renders only the component without children, enabling isolated unit tests. Full DOM rendering mounts entire component tree including children, enabling integration tests. Choose based on test needs: shallow for unit tests, full for integration tests.
TestRenderer is React's utility for rendering components and capturing output for testing. It provides API for rendering components and inspecting output without DOM. Useful for testing component output and snapshots in non-browser environments.