React Interview Questions
Question: What is the useEffect
hook in React?
Answer:
The useEffect
hook is one of the most important hooks in React. It allows you to perform side effects in functional components, such as fetching data, updating the DOM, subscribing to events, or cleaning up resources like timers and subscriptions. It is React’s answer to lifecycle methods (componentDidMount
, componentDidUpdate
, and componentWillUnmount
) in class components.
Syntax:
useEffect(() => {
// Code to run when the component mounts or updates
return () => {
// Cleanup function (optional)
};
}, [dependencies]);
- First argument (
() => { ... }
): This is a function that will be executed after the render. It is where you put your side-effect code, such as data fetching, subscriptions, or DOM manipulations. - Return value (optional): A cleanup function that will run when the component unmounts or before the effect runs again (for example, to unsubscribe from events or clear timers).
- Second argument (
[dependencies]
): This is an optional array of dependencies. The effect will only run when the specified values in the array change. If you pass an empty array[]
, the effect will only run on mount and unmount (equivalent tocomponentDidMount
andcomponentWillUnmount
in class components). If you omit the array, the effect will run after every render (likecomponentDidUpdate
).
How useEffect
Works:
-
Runs after every render by default: By default, the effect runs after every render of the component, but you can customize this behavior using the dependencies array.
-
Cleanup: If the effect includes a return statement with a cleanup function, that cleanup function will run before the component unmounts or before the effect is re-executed.
Example 1: Basic Usage of useEffect
Here’s a basic example where we use useEffect
to run a side effect when a component mounts:
import React, { useState, useEffect } from 'react';
const Example = () => {
const [count, setCount] = useState(0);
// Effect that runs after the component mounts or updates
useEffect(() => {
console.log('Component has mounted or updated!');
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Example;
In this case, useEffect
will run after every render, logging to the console each time the component updates.
Example 2: Running useEffect
Only on Mount (Equivalent to componentDidMount
)
If you want the effect to run only when the component mounts and not on subsequent updates, you can pass an empty array []
as the second argument:
import React, { useEffect } from 'react';
const Example = () => {
useEffect(() => {
console.log('Component has mounted!');
}, []); // Empty array means this effect only runs on mount
return <div>Hello, world!</div>;
};
export default Example;
Here, the effect will run only once after the component mounts, mimicking the behavior of componentDidMount
in class components.
Example 3: Running useEffect
When Dependencies Change (Equivalent to componentDidUpdate
)
If you want the effect to run only when certain props or state variables change, pass those dependencies in the second argument:
import React, { useState, useEffect } from 'react';
const Example = () => {
const [count, setCount] = useState(0);
// Effect that runs only when 'count' changes
useEffect(() => {
console.log(`Count has changed to: ${count}`);
}, [count]); // Effect runs when 'count' changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Example;
In this example, the effect will run only when the count
state variable changes.
Example 4: Cleanup in useEffect
(Equivalent to componentWillUnmount
)
Sometimes, you need to clean up resources (e.g., unsubscribing from a service, clearing timers) when the component unmounts or when a dependency changes. You can do this by returning a cleanup function from the useEffect
callback.
import React, { useState, useEffect } from 'react';
const Example = () => {
const [count, setCount] = useState(0);
// Set up a timer and clean it up when the component unmounts or count changes
useEffect(() => {
const timer = setInterval(() => {
console.log('Timer is running');
}, 1000);
// Cleanup function to clear the timer
return () => {
clearInterval(timer);
console.log('Timer has been cleared');
};
}, [count]); // Runs when 'count' changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Example;
Here:
- A timer is set up when the component is mounted, and the timer is cleared when the component unmounts or when the
count
state changes.
Key Points about useEffect
:
-
Side Effects:
useEffect
is used to handle side effects, such as fetching data, directly interacting with the DOM, or subscribing to external services (e.g., WebSocket, event listeners). -
Effect Cleanup: If your effect has a side effect that needs cleanup (like timers, event listeners, subscriptions), return a function from the effect callback. This function will be called when the component unmounts or before the effect runs again.
-
Dependencies: The second argument (
dependencies
) is crucial in controlling when the effect runs. If you pass an empty array[]
, the effect will only run on mount and unmount. If you pass specific dependencies, the effect will only run when one of those dependencies changes. -
Async Code in
useEffect
: WhileuseEffect
itself cannot return a Promise, you can define an asynchronous function inside the effect and call it:useEffect(() => { const fetchData = async () => { const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); }; fetchData(); }, []);
-
Multiple Effects: You can use multiple
useEffect
hooks in the same component to handle different side effects independently.useEffect(() => { // Effect 1: Fetch data from an API }, []); useEffect(() => { // Effect 2: Set up an event listener }, [dependency]);
Summary:
The useEffect
hook in React allows you to perform side effects in functional components. It runs after the render and can be customized to run only when certain dependencies change or when the component mounts and unmounts. The hook also supports cleanup, making it ideal for managing resources like timers, subscriptions, and fetching data.
By using useEffect
, you can create more interactive and dynamic components that perform tasks like data fetching, event handling, and resource management, all while keeping your components declarative and clean.
Question: What are controlled and uncontrolled components in React?
Answer:
In React, controlled and uncontrolled components refer to the way form elements (such as input fields, textareas, and select boxes) handle their state.
Controlled Components:
A controlled component is an input element whose value is controlled by the state of the React component. In other words, the React state is the “single source of truth” for the input’s value. When the value of the input changes, it triggers an event (usually onChange
) that updates the state, and the state in turn updates the input’s value.
In a controlled component, the value of the form element is set by a state variable, and changes to the input field are handled through state updates. Every input change will cause the component to re-render, making the form element’s value reflect the latest state.
Example of a Controlled Component:
import React, { useState } from 'react';
const ControlledInput = () => {
const [inputValue, setInputValue] = useState('');
// Handle the change in the input field
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input
type="text"
value={inputValue} // Value of input is controlled by React state
onChange={handleChange} // Update state on change
/>
<p>Entered Text: {inputValue}</p>
</div>
);
};
export default ControlledInput;
Key Characteristics of Controlled Components:
- Value is controlled by React state: The
value
of the form element is tied to a state variable. - State updates trigger re-renders: Any change in the form element triggers a state update and a re-render of the component.
- Form handling is done via React: All form-related logic (validations, updates, etc.) is handled via React state.
- Better control over input values: You can enforce constraints, validation, or custom behaviors directly via React logic.
Uncontrolled Components:
An uncontrolled component is an input element where the form element itself maintains its own internal state. Instead of tying the input value to a React state variable, an uncontrolled component relies on the DOM to manage the value. React does not directly control the form element’s state, but you can still interact with it using a ref.
In an uncontrolled component, the value of the form element is accessed through a ref when needed (for example, during form submission).
Example of an Uncontrolled Component:
import React, { useRef } from 'react';
const UncontrolledInput = () => {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
// Access the value of the input using ref
alert('Entered Text: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
ref={inputRef} // Use ref to interact with the input element
/>
<button type="submit">Submit</button>
</form>
);
};
export default UncontrolledInput;
Key Characteristics of Uncontrolled Components:
- Value is not controlled by React state: The form element manages its own state internally.
- React doesn’t directly handle form updates: The input element’s state (value) is handled by the DOM, not React.
- Access via
ref
: You can access and interact with the form element’s value via a ref when needed, such as on form submission. - Simpler for certain cases: Uncontrolled components are often easier to set up when you don’t need to track or modify the value while the user is interacting with the input.
Differences between Controlled and Uncontrolled Components:
Feature | Controlled Components | Uncontrolled Components |
---|---|---|
State management | React state controls the form element’s value | DOM manages the value of the form element |
Value | Tied to React state (value attribute) | Managed by the DOM (via refs) |
Form handling | Form state is updated via React (onChange ) | Use refs to interact with form values at a later time (e.g., inputRef.current.value ) |
Re-renders | Re-renders the component on each input change | No re-render triggered when the input value changes |
Use case | Best for cases where form values need to be dynamically controlled or validated by React | Best for simple forms where React does not need to control the input value continuously |
Complexity | More complex (state management and event handling required) | Simpler, with less React overhead |
Use of ref | Rarely used (though it can still be used in specific cases) | Frequently used to access form values or elements |
When to Use Controlled vs. Uncontrolled Components:
-
Controlled Components:
- When you need to manage the input’s value dynamically.
- When you need validation, formatting, or other behavior that should depend on the current value.
- When you want to enforce consistent state across your component (e.g., ensuring that only certain input values are valid).
-
Uncontrolled Components:
- For simpler forms where you do not need to manage the form’s value actively.
- When you want to interact with the input only at specific times (e.g., on form submission) rather than on every change.
- For integrating React into existing non-React codebases or libraries that manage form values independently.
Summary:
- Controlled components are those whose value is tied to a React state variable. React manages the form element’s value, making it possible to apply validation and other logic.
- Uncontrolled components are those that store their value in the DOM, and React only interacts with them via refs when needed.
Controlled components offer more flexibility and are the preferred choice in most React applications due to their clear integration with React’s state management system. However, for simple use cases or when performance is a concern (such as in large forms with a lot of inputs), uncontrolled components can be a simpler and more efficient choice.
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