Top ReactJS Interview Questions for Developers
Question: What are higher-order components (HOCs) in React?
Answer:
A Higher-Order Component (HOC) is a function in React that takes a component and returns a new component with additional functionality. HOCs are a pattern used for reusing component logic. They don’t modify the original component directly; instead, they enhance the component by adding extra behavior or props.
Key Characteristics of HOCs:
- Pure Functions: HOCs are pure functions, meaning they do not modify the original component but return a new component with enhanced behavior.
- Reusable Logic: HOCs allow you to abstract out reusable logic and apply it to multiple components without duplicating code.
- Props Management: They can modify or inject props into the wrapped component, enabling you to enhance or control its behavior.
Syntax:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
Common Use Cases for HOCs:
- Conditional Rendering: Add logic to display a loading indicator, error boundary, or authentication check.
- Code Splitting: Dynamically load components only when needed.
- State Management: Share state or business logic across multiple components without duplicating code.
- Props Manipulation: Modify or inject props into the wrapped component.
Example of a Higher-Order Component:
Let’s say we want to create a HOC that adds a loading
state to a component, displaying a loading spinner until data is fetched.
import React, { useState, useEffect } from 'react';
// HOC that adds loading functionality
const withLoading = (WrappedComponent) => {
return (props) => {
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate a data fetching
setTimeout(() => setLoading(false), 2000);
}, []);
if (loading) {
return <div>Loading...</div>;
}
// If not loading, render the wrapped component
return <WrappedComponent {...props} />;
};
};
// A simple component
const UserList = () => {
return <div>User List Content</div>;
};
// Wrap the UserList component with the loading HOC
const UserListWithLoading = withLoading(UserList);
// Usage in the app
const App = () => {
return (
<div>
<h1>My App</h1>
<UserListWithLoading />
</div>
);
};
export default App;
How HOCs Work:
- The
withLoading
HOC takes theUserList
component as an argument. - It returns a new component that has additional behavior (showing a loading indicator until the state changes).
- When the component is rendered, it checks the
loading
state, and if the state istrue
, it shows the “Loading…” text. Once the data is “fetched” (simulated bysetTimeout
), it renders the originalUserList
component.
Benefits of HOCs:
- Code Reusability: HOCs enable the reuse of logic that can be applied to multiple components.
- Separation of Concerns: By using HOCs, you can separate concerns like authentication, state management, and lifecycle management from the component’s presentation logic.
- Enhanced Readability: HOCs can make components more concise and easier to read by abstracting out logic into reusable functions.
Important Considerations:
- Don’t Mutate the Original Component: HOCs should never modify the original component directly. Instead, they return a new component with enhanced functionality.
- Props Handling: When creating a HOC, you must ensure that all props from the wrapped component are passed down correctly using
...props
. - Naming Conventions: It’s common practice to give the HOC a name that reflects its functionality. For example,
withLoading
,withAuth
,withErrorBoundary
.
Drawbacks of HOCs:
- Wrapper Hell: HOCs can result in deeply nested components, which may make the component tree harder to debug and understand (though React hooks can often help mitigate this).
- Static Methods and Ref Forwarding: If your component has static methods or refs, HOCs may need additional handling (e.g., using
forwardRef
to pass refs down the component tree).
Conclusion:
Higher-Order Components are a powerful pattern in React for reusing logic across components. They allow developers to compose components with additional behavior, improving code maintainability and reducing duplication. However, with the advent of React hooks, some use cases for HOCs are being replaced by more flexible and cleaner solutions.
Question: What are React Hooks?
Answer:
React Hooks are functions that allow you to use state and other React features in functional components, which were previously only available in class components. They were introduced in React 16.8 to provide a simpler, more readable way to manage state, side effects, context, refs, and other React features in functional components.
Before Hooks, managing state and lifecycle methods required class components. With Hooks, you can now use all of these features in functional components without needing to write classes.
Commonly Used React Hooks:
-
useState: The
useState
hook is used to add state to functional components. It returns an array with two elements: the current state value and a function to update it.import React, { useState } from 'react'; const Counter = () => { const [count, setCount] = useState(0); // Initial state is 0 return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); };
useState(0)
initializes the state with a value of0
.setCount
is the function used to update the state.
-
useEffect: The
useEffect
hook is used to perform side effects in function components, such as data fetching, subscriptions, or manually updating the DOM. It replaces lifecycle methods likecomponentDidMount
,componentDidUpdate
, andcomponentWillUnmount
in class components.import React, { useState, useEffect } from 'react'; const DataFetcher = () => { const [data, setData] = useState(null); useEffect(() => { fetch('https://api.example.com/data') .then(response => response.json()) .then(data => setData(data)); }, []); // The empty array means this effect runs once, similar to componentDidMount return ( <div> {data ? <p>{data}</p> : <p>Loading...</p>} </div> ); };
- The
useEffect
hook runs after the component renders. - The second argument (
[]
) is a dependency array. If empty, the effect runs once after the initial render, simulatingcomponentDidMount
.
- The
-
useContext: The
useContext
hook allows you to subscribe to a context value without needing to use aContext.Consumer
. It provides a simpler way to manage global state.import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); const ThemedComponent = () => { const theme = useContext(ThemeContext); return ( <div> <p>The current theme is: {theme}</p> </div> ); };
useContext(ThemeContext)
allows you to access the value provided byThemeContext.Provider
.
-
useRef: The
useRef
hook is used to create mutable object references that persist across re-renders. It is commonly used to access DOM elements directly, similar toReact.createRef()
in class components.import React, { useRef } from 'react'; const InputFocus = () => { const inputRef = useRef(null); const focusInput = () => { inputRef.current.focus(); }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={focusInput}>Focus the input</button> </div> ); };
useRef
returns a mutableref
object. Thecurrent
property is used to store a reference to the DOM element.
-
useReducer: The
useReducer
hook is an alternative touseState
, used for managing more complex state logic. It is similar to how Redux works, using a reducer function to specify how the state should change based on actions.import React, { useReducer } from 'react'; const counterReducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; } }; const Counter = () => { const [state, dispatch] = useReducer(counterReducer, { count: 0 }); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> </div> ); };
useReducer
is useful for managing state with complex logic, such as when you need to handle multiple actions that affect the same piece of state.
-
useMemo: The
useMemo
hook memoizes the result of an expensive function call to prevent it from being recalculated on every render.import React, { useMemo } from 'react'; const ExpensiveComponent = ({ num }) => { const calculate = (n) => { console.log('Expensive calculation'); return n * 2; }; const result = useMemo(() => calculate(num), [num]); return <div>Result: {result}</div>; };
useMemo
ensures that thecalculate
function is only called whennum
changes, optimizing performance.
-
useCallback: The
useCallback
hook is used to memoize functions, ensuring that a function is not re-created on every render.import React, { useState, useCallback } from 'react'; const Button = ({ onClick }) => { console.log('Button rendered'); return <button onClick={onClick}>Click me</button>; }; const App = () => { const [count, setCount] = useState(0); const handleClick = useCallback(() => { setCount(count + 1); }, [count]); return ( <div> <p>Count: {count}</p> <Button onClick={handleClick} /> </div> ); };
useCallback
memoizes thehandleClick
function to prevent unnecessary re-creations of the function on each render.
Benefits of React Hooks:
- Cleaner Code: Hooks provide a cleaner and more concise way to write React components without the need for classes.
- Reusability: Hooks allow you to reuse stateful logic between components without modifying the component hierarchy.
- Better Readability: Hooks help avoid the complexity of class-based components, making code more readable and easier to understand.
- Functional Components: You can now perform side effects, manage state, and interact with context in functional components, making them as powerful as class components.
Conclusion:
React Hooks revolutionized how we work with functional components by bringing state and lifecycle methods into them. They offer a more flexible, cleaner, and reusable approach for writing React components. By using hooks like useState
, useEffect
, useContext
, and useReducer
, developers can manage state, side effects, and context in a functional, declarative way without the need for classes.
Read More
If you can’t get enough from this article, Aihirely has plenty more related information, such as ReactJS interview questions, ReactJS interview experiences, and details about various ReactJS job positions. Click here to check it out.
Tags
- React
- ReactJS
- JavaScript
- Frontend Development
- Web Development
- React Components
- State and Props
- JSX
- Virtual DOM
- React Lifecycle
- UseState
- UseEffect
- React Router
- Redux
- Higher Order Components
- React Hooks
- Context API
- Pure Components
- Controlled Components
- Uncontrolled Components
- Forms in React
- React Performance
- React Key Prop
- React Reconciliation
- Server Side Rendering
- SPA
- Single Page Applications
- React Interview Questions
- React Features
- React Tutorial
- React Performance Optimization