Preparing for a React interview can be daunting, but having access to the right questions can make all the difference. We've curated a prioritized list of over 100 questions, covering essential topics like React fundamentals, hooks, React Router, React internationalization, and React testing. This comprehensive guide is designed to help you prepare effectively, boost your confidence, and ensure you make a strong impression during your interview.
React is a JavaScript library developed by Facebook for creating user interfaces, particularly in single-page applications. It enables the use of reusable components that manage their own state. Key advantages include a component-driven architecture, optimized updates through the virtual DOM, a declarative approach for better readability, and robust community backing.
JSX, short for JavaScript XML, is a syntax extension for JavaScript that allows you to write HTML-like code within JavaScript. It makes building React components easier. JSX gets converted into JavaScript function calls, often by Babel. For instance, <div>Hello, world!</div>
is transformed into React.createElement('div', null, 'Hello, world!')
.
The virtual DOM is a simplified version of the actual DOM used by React. It allows for efficient UI updates by comparing the virtual DOM to the real DOM and making only the necessary changes through a process known as reconciliation.
The virtual DOM operates by generating a new tree when a component's state changes and then comparing it to the previous tree using "reconciliation." This process ensures that only the differences are reflected in the actual DOM, boosting performance. While it offers benefits like increased efficiency and a declarative approach to UI management, it can add complexity to simpler applications.
A React Node refers to any unit that can be rendered in React, such as an element, string, number, or null
. A React Element is an immutable object that defines what should be rendered, typically created using JSX or React.createElement
. A React Component is either a function or class that returns React Elements, enabling the creation of reusable UI components.
React Fragments allow you to group multiple elements without adding extra nodes to the DOM. They are particularly useful when you need to return multiple elements from a component but don't want to wrap them in a container element. You can utilize shorthand syntax <>...</>
or React.Fragment
.
key
prop in React?In React, the key
prop is used to uniquely identify elements in a list, allowing React to optimize rendering by updating and reordering items more efficiently. Without unique keys, React might re-render elements unnecessarily, causing performance problems and potential bugs.
Using array indices as key
s can lead to performance issues and unexpected behavior, especially when reordering or deleting items. React relies on keys to identify elements uniquely, and using indices can cause components to be re-rendered unnecessarily or display incorrect data.
Props (short for properties) are inputs to React components that allow you to pass data from a parent component to a child component. They are immutable and are used to configure a component. In contrast, state is internal to a component and can change over time, typically due to user interactions or other events.
Class components are ES6 classes that extend React.Component
and can hold state, lifecycle methods, and other features. Functional components are simpler, functional JavaScript components that take props as input and return JSX. With the introduction of hooks, functional components can now manage state and lifecycle methods, making them more versatile.
Class components are useful when you need to manage state, use lifecycle methods, or optimize performance through shouldComponentUpdate
. However, with the introduction of hooks, functional components can now handle state and lifecycle methods, making them a preferred choice for most use cases due to their simplicity and readability.
React Fiber is a complete rewrite of the React core algorithm, designed to improve performance and enable new features like async rendering, error boundaries, and incremental rendering. It breaks down the rendering process into smaller chunks, allowing React to pause, abort, or prioritize updates as needed.
Reconciliation is the process by which React updates the DOM to match the virtual DOM efficiently. It involves comparing the new virtual DOM tree with the previous one and determining the minimum number of changes required to update the actual DOM. This process ensures optimal performance by avoiding unnecessary re-renders.
The Shadow DOM is a web standard that encapsulates a part of the DOM, isolating it from the rest of the document. It's used for creating reusable, self-contained components without affecting the global styles or scripts.
The Virtual DOM is an in-memory representation of the actual DOM used to optimize rendering. It compares the current and previous states of the UI, updating only the necessary parts of the DOM, which improves performance.
In controlled components, form data is managed through the component's state, making it the definitive source of truth. Input value changes are handled by event handlers. In uncontrolled components, the form state is managed internally and accessed via refs. Controlled components provide more control and are easier to test, while uncontrolled components are simpler for basic use cases.
Example of a controlled component:
Example of an uncontrolled component:
Lifting state up in React involves moving the state from child components to their nearest common ancestor. This pattern is used to share state between components that don't have a direct parent-child relationship. By lifting state up, you can avoid prop drilling and simplify the management of shared data.
Example:
In this example, the state is managed in the Parent
component, and both child components access it via props.
Pure Components in React are components that only re-render when their props or state change. They use shallow comparison to check if the props or state have changed, preventing unnecessary re-renders and improving performance.
React.PureComponent
to become pureReact.memo
for the same effectExample:
createElement
and cloneElement
?The difference between createElement and cloneElement in React is as follows:
createElement
:cloneElement
:PropTypes
in React?PropTypes in React is used for type-checking props passed to components, ensuring the correct data types are used and warning developers during development.
Example:
It helps catch errors early, improving code quality.
Stateless components in React are components that do not manage or hold any internal state. They simply receive data via props and render UI based on that data. These components are often functional components and are used for presentational purposes.
Stateless components are simpler, easier to test, and often more reusable.
Stateful components in React are components that manage and hold their own internal state. They can modify their state in response to user interactions or other events and re-render themselves when the state changes.
Stateful components are essential for handling dynamic and interactive UIs.
The recommended ways for static type checking in React are:
TypeScript: A superset of JavaScript that adds optional static typing. It provides strong type checking, autocompletion, and other benefits at development time.
Example:
PropTypes: A runtime type-checking tool for React props, primarily for development purposes. It helps catch errors by checking prop types during development but doesn't offer full static analysis like TypeScript.
Example:
TypeScript is the preferred choice for static type checking due to its integration with the build process and comprehensive tooling, whereas PropTypes is useful for smaller projects or when you need runtime checks.
React advises against mutating state as it can lead to unexpected behaviors and bugs. State immutability helps efficiently determine when components need re-rendering; direct mutations may prevent React from detecting changes.
Hooks enable the use of state and other React features in functional components, removing the need for class components. They streamline code by reducing the reliance on lifecycle methods, enhance readability, and facilitate the reuse of stateful logic across components. Popular hooks like useState
and useEffect
are used for managing state and side effects.
React hooks should be called at the top level of a function, not inside loops, conditions, or nested functions. They must only be used within React function components or custom hooks. These guidelines ensure proper state management and lifecycle behavior.
useEffect
and useLayoutEffect
in React?useEffect
and useLayoutEffect
both handle side effects in React functional components but differ in when they run:
useEffect
runs asynchronously after the DOM has rendered, making it suitable for tasks like data fetching or subscriptions.useLayoutEffect
runs synchronously after DOM updates but before the browser paints, ideal for tasks like measuring DOM elements or aligning the UI with the DOM. Example:useEffect
affect?The dependency array of useEffect
controls when the effect re-runs:
useRef
hook in React and when should it be used?The useRef
hook creates a mutable object that persists through renders, allowing direct access to DOM elements, storing mutable values without causing re-renders, and maintaining references to values. For instance, useRef
can be utilized to focus on an input element:
setState()
in React and when should it be used?The callback function format of setState()
in React ensures that state updates are based on the most current state and props. This is essential when the new state depends on the previous state. Instead of passing an object directly to setState()
, you provide a function that takes the previous state and props as arguments, returning the updated state.
Using this approach helps avoid issues related to asynchronous updates, ensuring that your state reflects the latest values accurately.
useCallback
hook in React and when should it be used?The useCallback
hook memoizes functions to prevent their recreation on every render. This is especially beneficial when passing callbacks to optimized child components that depend on reference equality to avoid unnecessary renders. Use it when a function is passed as a prop to a child component.
useMemo
hook in React and when should it be used?The useMemo
hook memoizes costly calculations, recomputing them only when dependencies change. This enhances performance by avoiding unnecessary recalculations. It should be used for computationally intensive functions that don't need to run on every render.
useReducer
hook in React and when should it be used?The useReducer
hook manages complex state logic in functional components, serving as an alternative to useState. It's ideal when state has multiple sub-values or when the next state relies on the previous one. It accepts a reducer function and an initial state.
useId
hook in React and when should it be used?The useId
hook generates unique IDs for elements within a component, which is crucial for accessibility by linking form inputs with labels. It guarantees unique IDs across the application even if the component renders multiple times.
In React, re-rendering refers to the process of updating the user interface (UI) in response to changes in the component's state or props. When the state or props of a component change, React re-renders the component to reflect the updated data in the UI.
This involves:
forwardRef()
in React used for?forwardRef()
allows passing a ref through a component to one of its children. This is useful for accessing a DOM element or child component's instance directly from a parent.
To create and use custom hooks in React:
useState
or useEffect
Example:
Use the Hook:
Custom hooks let you reuse logic across components, keeping your code clean.
Error boundaries catch JavaScript errors in their child components, log them, and display fallback UI instead of crashing the application. They utilize componentDidCatch
and static getDerivedStateFromError
methods but do not catch errors in event handlers or asynchronous code.
React Suspense allows handling asynchronous operations more elegantly within components. It provides fallback content while waiting for resources like data or code to load. You can use it alongside React.lazy for code splitting.
Hydration involves attaching event listeners and making server-rendered HTML interactive on the client side. After server-side rendering, React initializes dynamic behavior by attaching event handlers.
React Portals allow rendering children into a DOM node outside the parent component's hierarchy. This is useful for modals or tooltips that need to escape parent overflow or z-index constraints.
React Strict Mode is a development feature in React that activates extra checks and warnings to help identify potential issues in your app.
Wrapping components in <React.StrictMode>
activates these development checks without affecting production builds.
Code splitting enhances performance by dividing code into smaller chunks loaded on demand, thereby reducing initial load times. This can be achieved through dynamic import() statements or using React's React.lazy and Suspense.
Optimizing context performance involves memoizing context values with useMemo, splitting contexts for isolated state changes, and employing selectors to rerender only necessary components.
The Flux pattern manages application state through unidirectional data flow, simplifying debugging and enhancing maintainability with clear separation of concerns between Dispatcher, Stores, Actions, and Views.
In React, one-way data flow means data moves from parent to child components through props.
Example:
This ensures data flows in one direction, making the app more predictable.
Context in React can lead to performance issues if not handled carefully, causing unnecessary re-renders of components that consume the context, even if only part of the context changes. Overusing context for state management can also make the code harder to maintain and understand. It's best to use context sparingly and consider other state management solutions like Redux or Zustand for more complex scenarios.
React anti-patterns are practices that can lead to inefficient or hard-to-maintain code. Common examples include:
Choosing between React state, context, and external state managers depends on your application's complexity. Use React state for local component state, context for global state shared across multiple components, and external managers like Redux or MobX for complex state management requiring advanced features.
setState
is called in React.When setState
is called in React:
Example:
In this example, calling setState
(via setCount
) triggers a re-render with the updated count
.
Prop drilling is when you pass data from a parent component to a deeply nested child component through props, even if intermediate components don't use it.
Example:
In this example, data
is passed through multiple components, even though only the Child
component uses it.
Lazy loading in React is a technique where components are loaded only when they are needed, rather than at the initial page load. This helps reduce the initial load time and improve performance by splitting the code into smaller chunks.
Example:
In this example, LazyComponent
is loaded only when it's rendered, and while loading, a fallback UI (Loading...) is displayed.
Synthetic events in React are a wrapper around native DOM events that ensure consistent behavior across browsers. They normalize the way events are handled, providing a unified API for React applications.
These events are wrapped in the SyntheticEvent
object and offer methods like preventDefault()
and stopPropagation()
to control event behavior. React uses event pooling to reuse event objects, which helps optimize performance.
Example:
In this example, handleClick
handles the click event consistently across all browsers using a synthetic event.
React class components have lifecycle methods for different phases:
constructor
: Initializes state or binds methodscomponentDidMount
: Runs after the component mounts, useful for API calls or subscriptionsshouldComponentUpdate
: Determines if the component should re-rendercomponentDidUpdate
: Runs after updates, useful for side effectscomponentWillUnmount
: Cleans up (e.g., removing event listeners).These methods allow you to manage component behavior throughout its lifecycle.
Concurrent Mode allows React to work on multiple tasks simultaneously without blocking the main UI thread. It enables React to prioritize updates and provide smoother rendering for complex applications.
React uses the priority system in Concurrent Mode to schedule updates. It can break up large updates into smaller chunks and give priority to user interactions (like clicks or input) to ensure the app remains responsive.
To avoid blocking the UI, use Web Workers, setTimeout
, or requestIdleCallback
for offloading heavy computations. Alternatively, break tasks into smaller parts and use React's Suspense or useMemo to only recompute when necessary.
Example using setTimeout
for deferring computation:
Server-side rendering (SSR) involves rendering components on the server before sending fully rendered HTML to clients, improving initial load times and SEO through efficient hydration processes.
Static generation pre-renders HTML at build time instead of runtime; this approach enhances performance by delivering static content quickly while improving SEO outcomes.
Higher-order components (HOCs) are functions that take a component and return a new one with added props or behavior, facilitating logic reuse across components.
In React, the presentational vs container component pattern distinguishes between components that focus on appearance (presentational components) and those that manage logic and state (container components). Presentational components render HTML and CSS, while container components handle data and behavior. This separation leads to a cleaner and more organized codebase.
Render props in React allow code sharing between components through a prop that is a function. This function returns a React element, enabling data to be passed to child components. This technique facilitates logic reuse without relying on higher-order components or hooks.
The composition pattern in React involves building components by combining smaller, reusable ones instead of using inheritance. This encourages creating complex UIs by passing components as children or props.
To re-render the view on browser resize, use the useEffect
hook to listen for the resize event and update state.
Example:
This updates the state and re-renders the component whenever the window is resized.
Asynchronous data loading uses useEffect
alongside useState
hooks; fetching data inside useEffect
updates state with fetched results ensuring re-renders occur with new data.
Common pitfalls in data fetching with React include failing to handle loading and error states, neglecting to clean up subscriptions which can cause memory leaks, and improperly using lifecycle methods or hooks. Always ensure proper handling of these states, clean up after components, and utilize useEffect
for side effects in functional components.
React Router is a popular routing library for React applications that enables navigation between different components based on the URL. It provides declarative routing, allowing you to define routes and their corresponding components in a straightforward manner.
React Router maps URL paths to components, enabling navigation in single-page apps. Dynamic routing allows you to use URL parameters to render components based on dynamic values.
Example:
Key Features:
:id
captures dynamic data from the URL.useParams
Hook: Accesses these dynamic values for rendering.Nested routes allow you to create hierarchies of components, and useParams
helps access dynamic route parameters.
<Outlet>
: Renders child routes within a parent layoutuseParams
: Retrieves route parameters for dynamic routingBrowserRouter: Uses the HTML5 History API to manage navigation, enabling clean URLs without the hash (#
). It requires server-side configuration to handle routes correctly, especially for deep linking.
HashRouter: Uses the hash (#
) portion of the URL to simulate navigation. It doesn't require server-side configuration, as the hash is never sent to the server. This makes it suitable for environments where server-side routing isn't possible (e.g., static hosting).
React Router is a routing library for React that provides a declarative API for defining routes and handling navigation. It manages components and URLs.
History library is a lower-level utility that only manages browser history (e.g., pushing and popping history entries). It doesn't handle UI rendering or routing, making it more generic and not React-specific.
React Router uses the history library internally but adds additional features like routing and component management.
<Router>
components of React Router v6?In React Router v6, the key <Router>
components are:
<BrowserRouter>
: Uses the HTML5 history API to keep the UI in sync with the URL. It's commonly used for web applications.<HashRouter>
: Uses URL hash fragments (#) to manage routing, making it suitable for static file hosting or legacy browsers that don't support the HTML5 history API.<MemoryRouter>
: Keeps the URL in memory (no address bar changes), useful for non-browser environments like tests or embedded apps.<StaticRouter>
: Used for server-side rendering (SSR), where routing is handled without a browser, typically in Node.js environments.Each of these routers serves different use cases but provides the same routing functionality within a React app.
The push and replace methods of the history library are used to manage the browser's history stack and control navigation.
push
:history.push('/new-page')
replace
:history.replace('/new-page')
In React Router v6, you can navigate programmatically by using the useNavigate
hook. First, import useNavigate
from react-router-dom
and call it to get the navigate function. Then, you can use navigate('/new-page')
to navigate to a different route.
For example:
In React Router v5, the useHistory
hook provides access to the history object, which you can use to push a new route. For example, history.push('/new-page')
will navigate to the specified route.
For example:
Both methods allow you to navigate programmatically in React Router.
To implement private routes, create a component that checks if the user is authenticated before rendering the desired route.
Example:
PrivateRoute
: Checks authentication and either renders the children (protected routes) or redirects to the login page.<Navigate>
: Replaces the deprecated <Redirect>
for redirecting in React Router v6+.Use the useLocation hook to get the current route, and conditionally apply styles for the active state.
Example:
To handle 404 errors or page not found in React Router, create a catch-all route at the end of your route configuration that renders a custom 404 component.
Example:
In this example, the NotFound
component is rendered when no other routes match the URL, indicating a 404 error.
In React Router v6, you can use the useSearchParams
hook to access query parameters from the URL.
Example:
This hook allows you to retrieve and manipulate query parameters in React Router v6.
To perform an automatic redirect after login in React Router, use the useNavigate
hook to navigate to the desired route after successful authentication.
Example:
In this example, the handleLogin
function navigates to the /dashboard
route after successful login.
In React Router v6, you can pass props to a route component using the element
prop in the <Route>
component.
Example:
In this example, the propValue
prop is passed to the MyComponent
component when rendering the /my-route
route.
Localization typically involves libraries like react-i18next or react-intl. Set up translation files for different languages and configure the library within your app using provided hooks or components.
React Intl is a library that provides internationalization (i18n) support for React applications. It helps in formatting numbers, dates, strings, and handling translation/localization. It integrates with the Intl
API in JavaScript to provide locale-specific data and translation management.
<FormattedMessage />
, <FormattedNumber />
, <FormattedDate />
, etc., to format content.useIntl
for formatting messages, numbers, or dates imperatively within components.FormattedMessage
as a placeholder using React Intl?You can use the FormattedMessage
component to handle placeholders within strings. Placeholders are replaced dynamically with variables in the translated string.
Example:
Here, {name}
is a placeholder, and John
will replace it.
You can access the current locale using the useIntl
hook or the IntlProvider
's locale
prop.
useIntl
:IntlProvider
:Here, locale="en"
defines the current locale.
You can format dates using the <FormattedDate />
component or the useIntl
hook's formatDate
method.
<FormattedDate />
component:useIntl
hook:These methods allow you to format the date in a locale-sensitive manner.
Testing React applications can be done using Jest and React Testing Library. Jest serves as the testing framework while React Testing Library provides utilities for testing components similarly to user interactions.
Jest is a JavaScript testing framework that provides a test runner, assertion library, and mocking support. It's commonly used for testing React applications due to its simplicity and integration with tools like React Testing Library.
React Testing Library is a testing utility for React that helps test components in a way that resembles how users interact with the application. It provides functions to render components, interact with them, and assert on the rendered output.
To test React components using React Testing Library, you can:
render
.getByText
, queryByRole
, etc.Example:
In this example, the test renders MyComponent
, clicks a button, and asserts that the text 'Clicked!' is present.
To test asynchronous code in React components, you can use async/await
with waitFor
from React Testing Library to handle asynchronous operations like data fetching or API calls.
Example:
In this example, the test waits for the data to be loaded before asserting that the text 'Data loaded' is present.
To mock API calls in React component tests, you can use Jest's jest.mock
to mock the API module and return mock data. This allows you to simulate API responses without making actual network requests.
Example:
In this example, the fetchData
function from the api
module is mocked to return 'mocked data' for testing purposes.
To test React hooks in functional components, you can use the renderHook
function from @testing-library/react-hooks
to render the hook and test its behavior.
Example:
In this example, the useCounter
hook is tested by rendering it with renderHook
and asserting that the counter increments correctly.
To test custom hooks in React, you can use the renderHook
function from @testing-library/react-hooks
to render the hook and test its behavior.
Example:
In this example, the useCustomHook
hook is tested by rendering it with renderHook
and asserting its behavior.
The Shallow Renderer in React testing is a technique that allows you to render a React component without rendering its child components. This helps isolate the component being tested, focusing only on its logic, behavior, and output, without interference from its dependencies. It is useful for testing component states, event handling, and props in isolation.
Here's an example of using Shallow Renderer with Enzyme:
Shallow Rendering renders the component without its children, making tests simpler and faster. The shallow
function is used to test the component's output, props, and event handling. In the example, the label of the button and the click event handler are tested in isolation, ensuring the component behaves as expected.
Snapshot Testing in React is a testing technique that captures the rendered output of a component and saves it as a snapshot. Subsequent test runs compare the current output with the saved snapshot to detect any unexpected changes. If the output differs from the snapshot, the test fails, indicating that the component's output has changed.
Here's an example of using Snapshot Testing with Jest:
In this example, the renderer.create
function renders the MyComponent
and converts it to a JSON tree. The toMatchSnapshot
function saves the snapshot of the component's output. Subsequent test runs compare the current output with the saved snapshot, ensuring the component's output remains consistent.
To test React components that use context, you can wrap the component in a context provider with the desired context values for testing. This allows you to simulate the context values and test the component's behavior based on those values.
Example:
In this example, the MyComponent
is wrapped in a MyContextProvider
with a specific context value for testing. The test verifies that the component renders correctly with the provided context value.
To test React components that use Redux, you can use the redux-mock-store
library to create a mock store with the desired state for testing. This allows you to simulate the Redux store and test the component's behavior based on the state.
Example:
In this example, the MyComponent
is wrapped in a Provider
with a mock Redux store containing the initial state { counter: 0 }
for testing. The test verifies that the component renders correctly with the provided Redux state.
The TestRenderer package in React is a utility for rendering components and capturing their output for testing purposes. It provides a simple API for rendering components and inspecting their rendered output, making it easier to write tests for React components.
Example:
In this example, the TestRenderer.create
function renders the MyComponent
and converts it to a JSON tree. The toMatchSnapshot
function saves the snapshot of the component's output for testing.