• 8 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 11/8/22

Trigger Effects With useEffect

Whenever a modification occurs in a prop or the state, the relevant component and its children re-render.

But what if we want to perform an action that is not part of the return? What happens after React has updated the DOM? For example, if we want to trigger an alert each time the cart is updated? Or even save it after each update? 

These types of actions are called side effects, and for this, we have  useEffect , which  lets us perform an action at any moment in the lifecycle of our components.  😉

Discover useEffect

Let’s give it a go. Say you want to create an alert when you add a plant to the cart and for that alert to display the cart total

All that’s required is a little line of code in  Cart.js  :

alert(`I have ${total}€ to pay 💸`)

We’ll put that directly into our component, before the  return. Go on – try it!

When I click, it blocks my code and the total only displays once I’ve clicked OK! 😱 What’s going on? 

Don't worry, we won’t leave it like that.

This is where useEffect  comes into play. 

Import it like we did with  useState in  Cart.js  .

import { useState, useEffect } from 'react'

 Use this snippet instead (still in  Cart.js ):

useEffect(() => {
    alert(`I have ${total}€ to pay 💸`)
})

Which gives  Cart.js :

function Cart({ cart, updateCart }) {
    const [isOpen, setIsOpen] = useState(true)
    const total = cart.reduce(
        (acc, plantType) => acc + plantType.amount * plantType.price,
            0
        )
        
    return isOpen ? (
        <div className='jh-cart'>
            <button
                className='jh-cart-toggle-button'
                onClick={() => setIsOpen(false)}
            >
                Close
            </button>
            {cart.length > 0 ? (
                <div>
                    <h2>Cart</h2>
                    <ul>
                        {cart.map(({ name, price, amount }, index) => (
                            <div key={`${name}-${index}`}>
                                {name} {price}€ x {amount}
                            </div>
                        ))}
                    </ul>
                    <h3>Total:{total}€</h3>
                    <button onClick={() => updateCart([])}>Open Cart</button>
                </div>
            ) : (
                <div>Your cart is empty</div>
            )}
        </div>
    ) : (
        <div className='jh-cart-closed'>
            <button
                className='jh-cart-toggle-button'
                onClick={() => setIsOpen(true)}
            >
                Open Cart
            </button>
        </div>
    )
}

It’s working, and for the simple reason that  useEffect lets you perform your effect once the component has finished rendering. And because useEffect is directly within the component, you have direct access to your state, variables, and props. Fantastic, isn’t it?  

But wait, what happens if I close my cart? 

Nooooo! 😫  My alert triggers again!

Of course – useEffect  triggers every time the component renders.  

Specify When to Trigger an Effect With Dependencies

To decide exactly when you want an effect to be triggered, you can use a list of dependencies. This is the second parameter passed to  useEffect .

 That function is the effect to be run. In this case:

() => {
    alert(`I have ${total}€ to pay 💸`)
}

The second parameter of  useEffect  accepts a list written between square brackets: this is your list of dependencies. 

If you want to only display an alert when your cart total changes, all you have to do is: 

useEffect(() => {
    alert(`I have ${total}€ to pay 💸`)
}, [total])

You can put whatever variable you want here. If you want to display an alert when the total changes or when a new category is selected, it’s no problem to:

  • Get the selected category (by lifting up  activeCategory and setActiveCategory and passing them as props).

  • Put[total, activeCategory] in your list of dependencies. 

Give it a go and see for yourself!

The alert will be displayed either when the category or the total changes.

Will this effect be triggered after the first time my component renders? 

Try refreshing the page to see! The alert displays, so the answer is yes.

Although this question leads to another one:

How do I run an effect only after the first time my component renders? For example, if I want to get data on an API?

 For this, you need to provide an empty list of dependencies: 

useEffect(() => {
    alert('Welcome to Jungle House')
}, [])

Change the Title of Your Tab

Are you getting fed up with all these alerts? Wouldn't you rather use  useEffect  to update the title of your browser tab? 

A browser tab titled React App, with a React logo icon preceding the words.
React App in the browser tab.

To do this, use  document.title , still in  Cart.js :

useEffect(() => {
    document.title = `JH: ${total}€ Purchases`
}, [total])

Ta-da! The title of the tab changes according to the cart total! 🥳.

Play by the Rules With useEffect

Let’s go back over what you’ve just learned about useEffect as well as its other uses in this video!

As explained in the last chapter,  useEffect  is a hook, a function that allows you to hook into the functionality of React effects. However, there are a few special rules that apply.

  • Always call  useEffect  in the root of your component. You cannot call it inside a loop, conditional code, or nested functions. This way, you’ll avoid unwanted errors.  

  • Like for  useState ,  useEffect  is only accessible within a React function component. It’s not possible to use it within a class component or in a simple JavaScript function.  

A good practice is to separate the different actions being performed in different useEffects.

Give It a Go!

It’s now time to put what you’ve learned into practice. You’ll find the codebase on branch P3C3-Begin

Here, you’re going to let users save their cart, even when the page is refreshed using localStorage . To ensure the best possible user experience, you should do the following: 

  • Save the cart after each modification with  localStorage.setItem() . Careful – as your cart is now an object, you’ll have to use  JSON.stringify  (documentation can be found here) then  JSON.parse  (documentation here).

  • Ensure the cart is not saved more than required. 

  • Get the cart when the page is first loaded with  localStorage.getItem  .

 Once you’re done, compare your code on branch P3C3-Solution.

Let’s Recap!

  • Use  useEffect  to perform effects: it lets your component run actions after rendering, choosing when this action should be run. 

  • The hook useEffect is called after each time your component renders. It is possible to specify which data modification triggers the effects run in useEffect with a list of dependencies. 

  • An empty list of dependencies lets you run an effect only the first time your component is rendered. 

In the next part, we’ll have a quick recap of everything you’ve learned, and I’ll give you a few ideas of ways to continue your learning. See you there!  

Example of certificate of achievement
Example of certificate of achievement