Side Effects
Side effects are tasks that are required for app to work correctly, but don't directly impact current component render cycle.
- If a necessary function causes react to re-render again and again. Will cause an infinity loop.
- Which is a side-effect. If we want a function to only render once. We can use useEffect with an empty array. Or a trigger if it changes throughout runtime
You probably don't need useEffect, if you aren't trying to synchronize with some external system.
Effect Dependencies
- useEffect takes in a second parameter. An array with a list of dependencies. Whenever any dependency changes. useEffect function runs and component re-renders.
This is console every time a component re-renders
useEffect(() => {
console.log("render")
})This hook also takes a second parameter, Array. Whenever something inside that array changes, useEffect is called
useEffect(() ⇒ {
console.log("only once!")
}, []) // an empty array never changes, so only runs onceTo set some state to initial, whenever trigger changes
useEffect(() => {
setState(0);
}, [trigger]);You should add dependencies if you're using props or state functions inside useEffect.
Cleaning up Effect
You can return a function inside useEffect which can help clean up component after it is unmounted or right before useEffect re-executes
In this case, we want model to automatically conform after 3 seconds of opening. And we want Timeout to clear after we close model or unmount component.
useEffect(() => {
console.log("TIMER STARTED");
const timer = setTimeout(() => {
onConfirm();
}, 3000);
return () => {
console.log("TIMER CLEARED");
clearTimeout(timer);
};
}, []);Also be sure to only display dialog when open. Otherwise useEffect will run in background, since dialog is always open just not visible.
Now it works perfectly!
Problem with Object and Function Dependencies
When you pass object/function as dependency to an useEffect() there is a possibility for an infinite loop.
- useEffect - DeleteConfirmation.jsx
useEffect(() => {
const timer = setTimeout(() => onConfirm(), 3000);
return () => clearTimeout(timer);
}, [onConfirm]);- function - App.jsx
function handleRemovePlace() {
// ...
}Suppose you pass a function to useEffect and it re-executes, which causes entire component to re-render and which re-creates the function. In this case, even through the function is the exact same, javascript does not compare them as same. Which will cause useEffect to trigger and re-execute. And the whole process repeat infinitely.
And that's where useCallback comes in
useCallback
useCallback is a React Hook that lets you cache a function definition between re-renders.
Basically this stops functions to re-create whenever component re-renders, to stop useEffect with that as dependency to re-execute.
Talk about the 3 R's, am I right?
const handleRemovePlace = useCallback(function handleRemovePlace() {
// ...
}, []);Just wrap the function and pass in all reactive values referenced (state, prop, function, object, etc) inside an array as second parameter as dependencies.