A Breakdown of the React useEffect Hook
source link: https://www.telerik.com/blogs/breakdown-react-useeffect-hook
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
A Breakdown of the React useEffect Hook
React Hooks aim to solve the difficulties of logic reuse by enabling us to write components that have access to features like state, context, lifecycle methods, ref, etc. In this article, we’ll focus on the powerful useEffect hook, which allows us to perform side effects in our function components.
The concept of Hooks in React was introduced in early 2019 and for the last few years has been a commonly used utility in the world of React development.
For those who may be new to React, React Hooks aim to solve the difficulties of logic reuse by enabling us to write functional components that have access to features like state, context, lifecycle methods, ref, etc. without having to write a class component.
Many different hooks are immediately available to us when working with React, such as:
useState
HookuseEffect
HookuseContext
HookuseRef
Hook
React also gives us the capability to create our unique hooks to reuse custom stateful logic between components.
In the future, we’ll spend more time discussing all the different capabilities React Hooks give us, but for this article we’ll direct our attention to the powerful useEffect
hook.
useEffect Hook
The useEffect
hook allows us to perform side effects in our function components. Side effects are essentially anything where we want an “imperative” action to happen. API calls, updating the DOM, subscribing to event listeners—these
are all side effects that we might like a component to undergo at different times.
The useEffect
hook doesn’t return any values but instead takes two arguments. The first being required and the second optional.
- The first argument is the effect callback function we want the hook to run (i.e., the effect itself).
- The second (optional) argument is a dependency array that contains dependencies that when changed trigger the effect to rerun.
When written in code, the useEffect
hook looks like the following:
import React, { useEffect } from "react";
export const FunctionComponent = () => {
useEffect(() => {
// effect callback function
}, [] /* optional dependencies array */);
return (
// ...
);
}
There are three stages of a lifecycle of a React component where we may want to run a side effect:
- On every render
- Only on initial render
- On initial render and anytime a certain dependency changes
Run Effect on Every Render
Assume we wanted to place a console.log()
message within an effect callback in a function component.
import React, { useEffect } from "react";
export const FunctionComponent = () => {
useEffect(() => {
console.log("run for every component render");
});
return (
// ...
);
}
By default, the effect stated in a useEffect
hook runs when the component first renders and after every update. If we run the above code, we’ll notice the console.log()
message is generated as our component is rendered.
If our component was to ever re-render (for example due to a component state change), we’ll see the side effect run on every re-render that occurs.
Run Effect Only on First Render
The second argument of the useEffect
hook is optional and is a dependency list that allows us to tell React to skip applying the effect only until in certain conditions. In other words, the second argument of the useEffect
hook
allows us to limit when the effect is to be run. If we simply place a blank empty array as the second argument, this is how we tell React to only run the effect on initial render.
import React, { useEffect } from "react";
export const FunctionComponent = () => {
useEffect(() => {
console.log("run only for first component render (i.e. component mount)");
}, []);
return (
// ...
);
}
With the above code, the console.log()
message will only be fired when the component first mounts and won’t be generated again even if the component was to re-render multiple times.
Run Effect on First Render and Rerun When Dependency Changes
Instead of having an effect run once in the beginning and on every update, we can attempt to restrict the effect to run only in the beginning and when a certain dependency changes.
Assume we wanted to fire off a console.log()
message every time the value of a state property was to change. We can achieve this by placing the state property as a dependency of the effect callback.
import React, { useState, useEffect } from "react";
export const FunctionComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(
"run for first component render and re-run when 'count' changes"
);
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Click to increment count and trigger effect
</button>
);
};
Above, we have a button in the component template responsible for changing the value of the count
state property when clicked. Whenever the count
state property is changed (i.e., whenever the button is clicked), we’ll notice
the effect callback is run and the console.log()
message is fired!
Check out the useStateMachine hook
A lightweight state machine in React, useStateMachine essentially combines useReducer and useEffect.
If we had a different state property change, we’ll notice the effect callback won’t be rerun and the console.log()
message won’t fire since this property isn’t a dependency of the effect.
Run Effect with Cleanup
An effect callback gets run every time on the initial render of a component and when we’ve specified when an effect should run (i.e., when an effect dependency has changed). The useEffect
hook also provides the ability to run a cleanup
after the effect. This can be done by specifying a return function at the end of our effect.
import React, { useState, useEffect } from "react";
export const FunctionComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("run for every component render");
return () => {
console.log("run before the next effect and when component unmounts");
};
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Click to increment count and trigger effect
</button>
);
};
In the example above, we’ll notice the cleanup function message be fired before the intended effect is ever run. In addition, if our component ever unmounts—the cleanup function will run as well.
A good example of when we might need a cleanup is when we set up a subscription in our effect but want to remove the subscription whenever the next subscription call is to be made, to avoid memory leaks.
Wrap-up
This article covers all the different ways the useEffect
hook can be utilized to run side effects in components. At any time we want an “imperative” action to occur in our component (e.g., call an API, subscribe to an event listener,
etc.), we should automatically think of leveraging the useEffect
hook to run a side effect for a particular moment in the lifecycle of the React component.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK