Transitioning from Classes to Functions
In class components, lifecycle methods are normally used for mounting or updating components. While working with functional components there are no lifecycle methods and useEffect
hook is present which can be used for mounting or updating operations.
To start using the useEffect
hook in the functional components we need to import it from react as:
import { useEffect } from 'react';
Creating a basic side effect
In class components all the side effects are used by the lifecycle methods. This approach is fairly simple when a few side effects are involved, but when multiple side effects are involved that required to be cleaned up this approach gets confusing. With useEffect
, each side effect is defined along with it's clean up in it's own useEffect
hook.
The most basic side effect can be achieved by passing a single function to the useEffect
. This function is the side effect you want to run.
useEffect(() => {
console.log('This is your first side effect!')
});
This side effect will run each time the component renders that is when the component is first mounted or when the prop or state changes. This is not ideal if the side effect is only desirable when the component mounts or when a certain state/ prop changes. For this reason the useEffect
hook accepts an optional second parameter which is an array. The values of this array are compared during each re-render with the values of the array during the previous render and the side effect will only run if the values of the array differ from the ones during previous render. Hence to run the side effect on mount you need to pass an empty array as the second parameter so that the value would not change between subsequent re-renders. This can be achieved as:
useEffect(() => {
console.log('Run side effect on mount')
},[]);
By putting a value in the second array parameter of the useEffect
hook allows the side effect to run each time the value inside the array changes. This can be achieved as:
useEffect(() => {
console.log('Run side effect on value change')
},[value]);
Now let us have a look at a more complex example
const [userText, setUserText] = useState("");
const handleUserKeyPress = useCallback(event => {
const { key, keyCode } = event;
if(keyCode === 32 || (keyCode >= 65 && keyCode <= 90)){
setUserText(prevUserText => `${prevUserText}${key}`);
}
}, []);
useEffect(() => {
window.addEventListener("keyup", handleUserKeyPress);
}, [handleUserKeyPress]);
return (
<div>
<h1>Feel free to type!</h1>
<blockquote>{userText}</blockquote>
</div>
);
Here the side effect runs each time the value of the handleUserKeyPress
changes.
Cleaning the Side Effects
With the knowledge to set up the side effect, we now have to understand how to clean up the side effect. The useEffect
accepts a third parameter which is a return function which runs each time the side effect runs. Using our previous example:
useEffect(() => {
console.log('This is your first side effect!')
return () => {
console.log('This is your first clean up!')
}
});
Let us now have a look at how to implement a cleanup for our earlier window object side effect.
const [userText, setUserText] = useState("");
const handleUserKeyPress = useCallback(event => {
const { key, keyCode } = event;
if(keyCode === 32 || (keyCode >= 65 && keyCode <= 90)){
setUserText(prevUserText => `${prevUserText}${key}`);
}
}, []);
useEffect(() => {
window.addEventListener("keyup", handleUserKeyPress);
return () => {
window.removeEventListener("keydown", handleUserKeyPress);
};
}, [handleUserKeyPress]);
return (
<div>
<h1>Feel free to type!</h1>
<blockquote>{userText}</blockquote>
</div>
);
Here the return function is the clean up function which removes the event listener.
Conclusion
The useEffect
hook simplifies the side effects and clean up in components when props or state changes. In comparison to the lifecycle cycle methods in class components the useState
hook helps in organizing the side effects as each side effect gets its individual hook.
Top comments (0)