DEV Community 👩‍💻👨‍💻

Cover image for A quick explanation on useEffect
Dominik Biedebach
Dominik Biedebach

Posted on • Updated on

A quick explanation on useEffect

I got asked if I could write a quick explanation on the useEffect hook provided by React and thought "Sure, that should help a few people!".

useEffect can behave like componentDidMount shouldComponentUpdate and componentWillUnmount in one function if you set it up correctly. In this post I'll show you a few ways to replicate different lifecycle behaviours.

Keep in mind that useEffect uses the second argument dependencies as a performance tool

Here is an interesting read about how you can write your hooks in general even without dependencies:

Example as componentDidMount

First you can write an Effect that will just run once when the component mounted and will never run again:

useEffect(() => {
  console.log('I was mounted and will not run again!')
}, [])

Important here is the empty array as a second argument. The second argument of useEffect can be used to watch properties for changes. See the following.

Example as shouldComponentUpdate

useEffect can also help with watchers on your properties so you can run it everytime a specific value is updated. Let's say we have a prop called "name" and our component should update something via effect everytime the name prop changes you could do it like this:

const MyComponent = (props) => {
  useEffect(() => {
    document.title = `Page of ${}`
  }, [])

  return <div>My name is {} </div>

You can see that we passed into the array in the second argument. This will now cause the effect to always run again when the name changes.

Side note: You should always set the second argument because otherwise you can run into render loops.

Example as componentWillUnmount

useEffect can also be used to run code when the component dismounts. This is effective for subscriptions or other listeners (Websockets for example).

let bookSubscription = null
useEffect(() => {
  // stop the subscription if it already exists
  if (bookSubscription && bookSubscription.unsubscribe) bookSubscription.unsubscribe()

  // start a new subscription
  bookSubscription = startBookSubscription({ bookId: props.bookId })

  return () => {
    // stop the subscription when the component unmounts
}, [props.bookId])

You can see that now we used all options available. This code will now

  1. Start a new subscription when the component was mounted
  2. Update the subscription with the new bookId when the bookId prop changes
  3. unsubscribe the subscription when the component gets unmounted.

You can run logic whenever the component unmounts by returning a function in your effect.

I hope this quick post was helpful to you and helps you with further development. If you have questions, let me know!

Top comments (7)

samsch_org profile image
Samuel Scheiderich

Sorry to be "that guy", but I think you've got it pretty wrong.

Every useEffect you write should work correctly without using the dependencies argument. If something should only happen once, you should just do it, then set some state which tells you not to do it again.

useEffect is not lifecycles.

bdbch profile image
Dominik Biedebach

Hey, thanks for your comment.

While you're technically right - they are not lifecycles - they can be used to replicate lifecycles introduced by ClassComponents.

Also the dependencies argument should always be set, because a effect without dependencies will run on every render cycle.

Can you specify why my useEffect should also work without dependencies?

samsch_org profile image
Samuel Scheiderich

I just wrote an article the topic:

The purpose of the second argument is to be an optimization feature, not for control flow. This isn't state particularly explicitly in the React docs, but note that it's referred to as an optimization tool here and how the examples throughout the doc page don't use the deps arg.

Thread Thread
bdbch profile image
Dominik Biedebach

Hey Samuel, thanks that was an interesting read! I'll link to it in my article if thats fine.

I totally agree with you that dependency arguments are meant to be used as a performance tool, not lifecycles. In my post I just used lifecycles as an example on how the different parts of an effect work and how users can replicate lifecycles using them (and the return function).

Give me a few minutes to bring in your article into my post.

emma profile image
Emma Goto 🍙 • Edited on

Super easy to understand!

For the last example - it looks like startBookSubscription is being called each time the prop is changed (if I'm understanding correctly), maybe it should be renamed?

bdbch profile image
Dominik Biedebach

Thats right. I'll update the code with a better example! One second.

manojkrajasekar profile image
Manoj Kumar Rajasekar

Thanks for the Clean and Simple explaination !

18 Useful Github Repositories Every Developer Should Bookmark

18 Useful GitHub repositories every developer should bookmark: everything from learning resources and roadmaps to best practices, system designs, and tools.