Clientside Goodies

Practice React's useEffect hook with 4 Interactive Exercises

Master the useEffect hook in React with interactive exercises, covering scenarios like data fetching, input validation, and more, to enhance your functional components' performance and maintainability.

React hooks are a powerful feature that allows you to use state and lifecycle methods in functional components. Among the various hooks, the
useEffect
hook plays a crucial role in managing side effects in your application. Side effects can include data fetching, subscriptions, or manually changing the DOM – tasks that are usually performed outside the component but are necessary for its proper functioning.
In this blog post, we'll dive into the
useEffect
hook, its usage patterns, and how it can be used to handle various scenarios like data fetching, input validation, and more. To help you grasp these concepts, we've prepared interactive exercises that will guide you through the process of building components using the
useEffect
hook.

In the exercises, you will learn how to:

  1. Perform data fetching using
    useEffect
    and display the fetched data in your component.
  2. Create a timer component that updates the displayed time every second using
    useEffect
    .
  3. Build a form input validation component that validates user input and shows error messages using
    useEffect
    .
  4. Develop a component that listens to the window's resize event and displays the current window size using
    useEffect.

1. Data Fetching using useEffect

Easy
Create a
UserPosts
component that fetches and displays a list of posts for a given user ID using the JSONPlaceholder API (https://jsonplaceholder.typicode.com/). The component should fetch data when it mounts and update the data when the user ID prop changes. This exercise will help you understand how to use the
useEffect
hook for data fetching and the importance of the dependency array.

Expectations

  • Fetch data from the JSONPlaceholder API.

  • Display a list of posts for the given user ID.

  • Refetch data when the user ID prop changes.

Background

Understanding how to fetch data with
useEffect
is crucial as it is a common requirement in real-world applications. This exercise will help you learn how to fetch data on component mount and when the user ID prop changes, which is an essential pattern in React applications.
Console
Submit
Solution
00:00

Solution Walkthrough for Data Fetching using useEffect

Key Concepts

  1. Dependency Array: The dependency array is an optional second argument passed to
    useEffect
    that determines when the effect should run.
  2. Async/Await: The async/await syntax makes it easier to work with promises and fetch data from APIs.

  3. Fetch API: The Fetch API provides a simple interface for fetching resources, making it easier to perform HTTP requests.

Solution Walkthrough:

Initialize state variable
posts
with an empty array: We create a state variable
posts
using the
useState
hook and set its initial value to an empty array.
const [posts, setPosts] = useState([]);
Create an async function to fetch data and update the
posts
state: We use the
useEffect
hook to fetch data when the component mounts and when the
userId
prop changes. We create an async function
fetchData
inside the
useEffect
hook to fetch data from the JSONPlaceholder API using the Fetch API and the async/await syntax.
useEffect(() => {
  const fetchData = async () => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`);
    const data = await response.json();
    setPosts(data);
  };
  fetchData();
}, [userId]);
Render the list of posts: We use the
map
function to render the list of posts in the component.
return (
  <div>
    {posts.map((post) => (
      <div key={post.id}>
        <h3>{post.title}</h3>
        <p>{post.body}</p>
      </div>
    ))}
  </div>
);
This solution demonstrates the key concepts of using the
useEffect
hook for data fetching, controlling when the effect runs using the dependency array, and working with the Fetch API and async/await syntax to fetch data from an API.

2. Countdown Timer with useEffect

Easy
Create a
CountdownTimer
component that displays a countdown timer starting from a given initial value, and stops at 0. Use the
useEffect
hook to update the displayed time every second.

Expectations

  • Display the countdown timer, starting from the given initial value.

  • Update the timer every second using

    useEffect
    .
  • Stop the timer when it reaches 0.

  • Display the following text as the timer counts down: "Time Remaining: X"

  • Start the timer when the component mounts.

  • Stop the timer when the component unmounts.

Console
Submit
Solution
00:00

Solution Walkthrough for Countdown Timer with useEffect

Solution Explanation

Initialize state variable
timeRemaining
with the
initialValue
prop: We create a state variable
timeRemaining
using the
useState
hook and set its initial value to the
initialValue
prop.
const [timeRemaining, setTimeRemaining] = useState(initialValue);
Set up the
useEffect
hook to update the timer every second: We use the
useEffect
hook to create an interval that updates the
timeRemaining
state every second.
Before setting the interval, we check if
timeRemaining
is less than or equal to 0. If it is, we don't set the interval, effectively stopping the timer. We also return a cleanup function to clear the interval when the component unmounts or when
timeRemaining
changes. This ensures that there are no memory leaks or unnecessary intervals running.
useEffect(() => {
  if (timeRemaining <= 0) {
    return;
  }

  const timerId = setInterval(() => {
    setTimeRemaining((prevTime) => prevTime - 1);
  }, 1000);

  return () => {
    clearInterval(timerId);
  };
}, [timeRemaining]);
Display the current
timeRemaining
:
We use the
timeRemaining
state variable to display the current countdown timer value in a paragraph element.
<p>Time Remaining: {timeRemaining}</p>
This solution demonstrates the key concepts of using the
useEffect
hook for managing side effects like updating a timer every second, controlling when the effect runs using the dependency array, and cleaning up intervals to prevent memory leaks. Additionally, it showcases the ability to stop the timer when it reaches a specific value (0 in this case)

3. Window Resize Listener using useEffect

Medium
Create a
WindowSize
component that listens to the window's
resize
event and displays the current window size. Use the
useEffect
hook to add and remove the event listener on mount and unmount, respectively. This exercise will help you understand how to use the
useEffect
hook for managing side effects like event listeners and the importance of cleanup functions.

Expectations

  • Listen to the window's
    resize
    event.
  • Display the current window size.

  • Add the event listener when the component mounts.

  • Remove the event listener when the component unmounts.

Background

Using
useEffect
to manage side effects like event listeners is an essential skill for React developers. Event listeners are common in real-world applications, and this exercise will help you learn how to use
useEffect
for setting up and cleaning up event listeners in functional components.
Console
Submit
Solution
00:00

Solution Walkthrough for Window Resize Listener using useEffect

Solution Explanation

Initialize state variable
windowSize
with the current window size: We create a state variable
windowSize
using the
useState
hook and set its initial value to the current window size.
const [windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight });
Create a
handleResize
function and add the event listener: We use the
useEffect
hook to set up the event listener when the component mounts. Inside
useEffect
, we create a
handleResize
function that updates the
windowSize
state with the current window size. We then add the event listener to the window's
resize
event.
useEffect(() => {
  const handleResize = () => {
    setWindowSize({ width: window.innerWidth, height: window.innerHeight });
  };

  window.addEventListener('resize', handleResize);
  //...
}, []);
Return a cleanup function to remove the event listener: To ensure proper cleanup, we return a function that removes the event listener using
window.removeEventListener
. This cleanup function will be called when the component unmounts or if the effect is run again.
useEffect(() => {
  //...
  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);
Display the current window size: We use the
windowSize
state variable to display the current window size in a paragraph element.
<p>Window size: {windowSize.width} x {windowSize.height}</p>
This solution demonstrates the key concepts of using the
useEffect
hook for managing side effects like event listeners, controlling when the effect runs using the dependency array, and handling cleanup with a returned cleanup function.

4. Form Input Validation with useEffect

Easy

Prompt

Create a
ValidatedInput
component that validates user input and shows an error message if the input is invalid. Use the
useEffect
hook to perform validation whenever the input value changes, simulating
componentDidUpdate
behavior. This exercise will help you understand how to use the
useEffect
hook for performing validation based on changes in state and the importance of the dependency array.

Expectations

  • Validate user input based on a provided validation function.

  • Display an error message if the input is invalid.

  • Perform validation whenever the input value changes.

Background

Using
useEffect
to manage side effects like input validation is an essential skill for React developers. Validating user input is crucial for ensuring data quality and security in real-world applications, and this exercise will help you learn how to use
useEffect
for input validation in functional components.
Console
Submit
Solution
00:00

Solution Walkthrough for Form Input Validation with useEffect

Solution Explanation

Initialize state variables
value
and
isValid
: We create a state variable
value
using the
useState
hook and set its initial value to an empty string. We also create a state variable
isValid
to keep track of the input's validity.
const [value, setValue] = useState('');
const [isValid, setIsValid] = useState(true);
Validate input value with useEffect: We use the
useEffect
hook to perform validation whenever the input value changes. Inside
useEffect
, we call the provided
validationFunction
with the current input value and update the
isValid 
state accordingly. We include
value
and
validationFunction
in the dependency array to ensure the effect runs whenever either of them changes.
useEffect(() => {
  setIsValid(validationFunction(value));
}, [value, validationFunction]);
Create the input field and update the
value
state on change: We create an input field and update the
value
state with the input's value whenever it changes using the
onChange
event handler.
<input
  type="text"
  value={value}
  onChange={(e) => setValue(e.target.value)}
  className={isValid ? '' : 'error'}
/>
Display the error message if the input is invalid: We conditionally render the error message if the
isValid
state is false.
{!isValid && <p className="error-message">{errorMessage}</p>}
This solution demonstrates the key concepts of using the
useEffect
hook for managing side effects like input validation, controlling when the effect runs using the dependency array, and conditionally rendering error messages based on state changes.
By working through these examples, you should now have a solid understanding of how to manage side effects, control when the effect runs, and handle cleanup in your functional components. The
useEffect
hook is an essential tool in a React developer's arsenal, and knowing how to use it effectively will significantly enhance the performance and maintainability of your applications.
As you continue to build more complex applications, you may encounter additional scenarios where the
useEffect
hook can be utilized.

Don't hesitate to experiment with different use cases and explore the versatility of this powerful hook. By doing so, you will develop a deeper understanding of React, and you'll be well-equipped to tackle even the most challenging projects with confidence.

Keep learning, and happy coding!

Ready to dive deeper?

Explore our library of frontend interview problems taken from interviews at top tech companies. Level up your skills.