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 }
now only what matters:
useEffect(() => {
// do something async
})
but you could also see like this:
const callbackFunction = () => { }
useEffect(callbackFunction)
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)
This callbackFunction is called:
1 - once after each
render
const callbackFunction = () => { alert("2nd see this") }
useEffect(callbackFunction)
return <div>1st see this</div>
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>
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>
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>
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.
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])
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)])
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>
You will probally see the following error
React Hook useEffect has a missing dependency: 'myVar'.
Either include it or remove the dependency array.
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
Top comments (7)
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 asuseEffect(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 👍️
The post is full with bad advice. It's a good attempt, but a bad resource.
For example:
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.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.
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.
Glad to help 😊
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)]
Hi Ridoan,
Thank you, I fixed it. 👍