DEV Community

Cover image for Common UseEffects mistakes that even seniors are making
Hernani Fernandes
Hernani Fernandes

Posted on

Common UseEffects mistakes that even seniors are making

Learning useEffect in React leads us to assimilate several new concepts and for that reason we leave out small details that can cause big problems.

Most basic implementation:

import { useEffect } from "react"
const MyComponent = () => {
  useEffect(() => {
    // do something async
  })

  return <div> Hi! </div>
}
export { MyComponent }
Enter fullscreen mode Exit fullscreen mode

now only what matters:

useEffect(() => {
    // do something async
})
Enter fullscreen mode Exit fullscreen mode

but you could also see like this:

const callbackFunction = () => { }
useEffect(callbackFunction)
Enter fullscreen mode Exit fullscreen mode

What is useEffect?

It's a function that receives two parameters, at first position a callbackFunction and at second position a dependency array:

const callbackFunction = () => { }
const dependencies = [var1,var2,...] // var1, var2,... comes from outside
useEffect(callbackFunction, dependencies)
Enter fullscreen mode Exit fullscreen mode

This callbackFunction is called:

1 - once after each render

const callbackFunction = () => { alert("2nd see this") }
useEffect(callbackFunction)
return <div>1st see this</div>
Enter fullscreen mode Exit fullscreen mode

2 - once after first render

const callbackFunction = () => { alert("2nd see this") }
useEffect(callbackFunction, []) // with an empty array [] works like the previous example
return <div>1st see this</div>
Enter fullscreen mode Exit fullscreen mode

3 - once before that component is remove from the screen

 const doSomethingBeforeDestroy = async () => { // unsubscribe }
 const callbackFunction = () => { 
   alert("2nd see this") 
   return doSomethingBeforeDestroy
 }
 useEffect(callbackFunction, []) 
 return <div>1st see this</div>
Enter fullscreen mode Exit fullscreen mode

4 - every time when dependencies variables changes it values

 const [myVar, setMyVar] = useState("one")
 const handleClick =()=>{ 
   setMyVar("two")
 }
 const callbackFunction = () => { 
   alert("2nd see this but also after the click") 
 }
 useEffect(callbackFunction, [myVar]) 
 return <div click={handleClick}>1st see this and click</div>
Enter fullscreen mode Exit fullscreen mode

Most common mistakes:

Unsubscribe events

In example 3 you must be careful that you should always return an asynchronous function that never returns a value or change to any state because this component will be destroyed.

Warning: Can't perform a React state update on an unmounted component. 

Enter fullscreen mode Exit fullscreen mode

This useEffect return is usually used to unsubscribe socket events or change the store affecting external components but never the own component.

Unexpected renders

In example 4 you should always (ok, not always, there's one case that I will talk in another post) use primitives as dependencies never reference types such as *Functions, Objects or Arrays. Use only string, boolean, number.

Don't:

const myObject = { message :"hello" }
useEffect(callbackFunction, [myObject]) 
Enter fullscreen mode Exit fullscreen mode

Do:

const myObject = { message :"hello" }
useEffect(callbackFunction, [myObject.message])

// or 
const myObject = { message :"hello" }
useEffect(callbackFunction, [JSON.stringify(myObject.message)])  

//or 
const myArray = [1,2,3]
useEffect(callbackFunction, [JSON.stringify(myArray)]) 
Enter fullscreen mode Exit fullscreen mode

If you use one variable but not include it inside the dependencies like this

 const [myVar, setMyVar] = useState("one")
 const handleClick =()=>{ 
   setMyVar("two")
 }
 const callbackFunction = () => { 
   if (!myVar) setMyVar("new user")
 }
 useEffect(callbackFunction, []) // using myVar but not adding as a dependency 
 return <div click={handleClick}>1st see this and click</div>

Enter fullscreen mode Exit fullscreen mode

You will probally see the following error

React Hook useEffect has a missing dependency: 'myVar'. 
Either include it or remove the dependency array.
Enter fullscreen mode Exit fullscreen mode

Is sometimes necessary to use functions as dependencies then you should make it through useCallback that I will explain in my next article or simply ignore the eslint adding a comment like this:

const callbackFunction = () => { 
    if (!myVar) setMyVar("new user") 
}
useEffect(callbackFunction, [myVar]) // eslint-disable-line react-hooks/exhaustive-deps
// this comment above will ignore the error about the setMyVar function dependency
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
calag4n profile image
calag4n • Edited

I think you've made a mistake (or I didn't get your point) :

useEffect(callbackFunction) in here, callbackFunction is not executed only once after the first render but after each render ;
and
useEffect(callbackFunction, []) is not the same as useEffect(callbackFunction) , when you provide an empty array it's precisely in this case that your function is executed only once.

Some other writing mistakes with mixed up terms : myVar , var1 , var2 , var , myObject .

Nice post otherwise 👍️

Collapse
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

The post is full with bad advice. It's a good attempt, but a bad resource.

For example:

In example 3 you must always use primitives as dependencies never reference types such as *Functions, Objects or Arrays. Use only string, boolean, number.

You can use whatever you want as a dependency in the second argument of a useEffect hook, but if you want it to work as intended, the value must be stable: that is, not be regenerated each render. You can use functions, objects, and arrays.

Collapse
 
hernanif1 profile image
Hernani Fernandes • Edited

Hi Derk Jan,
Thank you for your feedback.
I updated this post so I removed that wrong typos and I'm trying to make my point clearer.
About the primitives as dependencies I'm trying to explain that most of the devs are simply filling in this parameter and are not aware about why.
Let me know if you have any resource that explains better about this specific part.

This is my first post so I was trying to make it fine instead of make it perfect because I procrastinated it for a long time.
Thank you for helping me to make it better.

Collapse
 
hernanif1 profile image
Hernani Fernandes

Hi calag4n, thank you for your feedback.
I didn't know about this difference between with /without array so thank you very much for teaching me that.
I updated the post.

Collapse
 
calag4n profile image
calag4n

Glad to help 😊

Collapse
 
ridoansaleh profile image
Ridoan • Edited

const myObject = { message :"hello" }
useEffect(callbackFunction, [var.message]) // typo => [myObject.message]

// or
const myObject = { message :"hello" }
useEffect(callbackFunction, [JSON.stringify(var.message)]) // typo => [JSON.stringify(myObject.message)]

Collapse
 
hernanif1 profile image
Hernani Fernandes

Hi Ridoan,
Thank you, I fixed it. 👍