React

useEffect

useEffect hook lets you perform side effects in functional components.

useEffect has 2 arguments:

  • effectFunction: a function to be called when one of the arrayDependencies changes its value (The side effects you want to perform). This function can also return another function, which is called a Cleanup Function, React will call Cleanup Function every time right before this side effect is performed again and when the component unmounts.
  • arrayDependencies (Optional): an array of dependencies you want to keep track of changes and perform side effects when their values change. If arrayDependencies is not present, the side effect will be performed every time the component re-render.
// Calling signature
useEffect(effectFunction, arrayDependencies)

Basic Side Effect

If there are no dependencies, the side effect will be always performed whenever the component re-render.

function Count() {
const [count, setCount] = useState(1)
const handleClick = () => setCount(count + 1)
useEffect(() => {
document.title = `Current count is ${count}`
})
return (
<div>
<div>Current count is {count}</div>
<Button onClick={handleClick}>+</Button>
<div>
Look at the title of the current tab to see the side effect
</div>
</div>
)
}

Effect with cleanup

Most side effects don't require any cleanup. However, some effects do. For example, we might want to set up a subscription to some external data source or add an event listeners to global elements. In that case, it is important to clean up so that we don't introduce a memory leak!

function Count() {
const [count, setCount] = useState(1)
useEffect(() => {
const handleClick = () => setCount(count + 1)
window.addEventListener("click", handleClick)
return () => {
window.removeEventListener("click", handleClick)
}
})
return (
<div>
<div>Current count is {count}</div>
<div>Click any where in the current window to increase count</div>
</div>
)
}

Multiple Effects

Multiple effects can be used within a component and make sure they are used to separate concerns. Don't combine multiple effects inside one big effect, since the dependencies of each effect can be different.

function Count() {
const [count, setCount] = useState(1)
useEffect(() => {
document.title = `Current count is ${count}`
})
useEffect(() => {
const handleClick = () => setCount(count + 1)
window.addEventListener("click", handleClick)
return () => {
window.removeEventListener("click", handleClick)
}
}, [])
return (
<div>
<div>Current count is {count}</div>
<div>Click any where in the current window to increase count</div>
</div>
)
}

Effects with Dependencies

If the arrayDependencies is empty, the effect will be performed only one time when the component is mounted. Otherwise, every time the component is re-rendered, React will keep checking for changes in arrayDependencies to decide whether it should perform the side effect or not.

function Count() {
const [count1, setCount1] = useState(1)
const [count2, setCount2] = useState(1)
const handleClick1 = () => setCount1(count1 + 1)
const handleClick2 = () => setCount2(count2 + 1)
useEffect(() => {
document.title = `Current count is ${count1} - ${count2}`
}, [count1])
return (
<div>
<div>Current count1 is {count1}</div>
<Button onClick={handleClick1}>+</Button>
<div>
Look at the title of the current tab to see the side effect
</div>
<div>Current count2 is {count2}</div>
<Button onClick={handleClick2}>+</Button>
<div>
The title will not change when clicking above button
</div>
</div>
)
}
Previous
useReducer