In general is it better to use one or many useEffect hooks in a single component?
Solution 1
The pattern that you need to follow depends on your use case.
First: You might have a situation where you need to add event listener during the initial mount and clean them up at unmount and another case where a particular listener needs to be cleaned up and re-added on a prop change.
In such a case, using two different useEffect
is better to keep the relevant logic together as well as having performance benefits
useEffect(() => {
// adding event listeners on mount here
return () => {
// cleaning up the listeners here
}
}, []);
useEffect(() => {
// adding listeners everytime props.x changes
return () => {
// removing the listener when props.x changes
}
}, [props.x])
Second: You need to trigger an API call or some other side-effect when any of the state or props change from a defined set. In such a case a single useEffect
with the relevant dependencies to monitor would be better
useEffect(() => {
// side effect here on change of any of props.x or stateY
}, [props.x, stateY])
Third: You need separate side-effect for different sets of changes. In such a case, separate out relevant side-effects into different useEffect
s
useEffect(() => {
// some side-effect on change of props.x
}, [props.x])
useEffect(() => {
// another side-effect on change of stateX or stateY
}, [stateX, stateY])
Solution 2
You should use multiple effects to separate concerns as suggested by reactjs.org.
Solution 3
It's perfectly fine to have have multiple useEffect.
Here's how one of my setups looks like:
/*
* Backend tags list have changed add the changes if needed
*/
useEffect(() => {
setTagsList(setTagsAdded);
}, [setTagsAdded]);
/*
* Backend files have changed add the changes if needed
*/
useEffect(() => {
for (let i = 0; i < changedFilesMeta.length; i += 1) {
// Is the list item value changed
if (changedFilesMeta[i].id === currentEditableFile.id) {
unstable_batchedUpdates(() => {
setTags(changedFilesMeta[i].tags ? changedFilesMeta[i].tags : []);
});
}
}
}, [changedFilesMeta]);
/*
* Reset when user select new files using the filepicker
*/
useEffect(() => {
if (setNewFiles.length > 0) {
unstable_batchedUpdates(() => {
setCurrentFile(null);
setDescription('');
setTitle('');
setTags([]);
});
}
}, [setNewFiles]);
/*
* User selecet to edit a file, change to that file
*/
useEffect(() => {
// When user select a file to edit it
if (currentEditableFile && currentEditableFile !== theCurrentFile) {
setCurrentFile(currentEditableFile);
unstable_batchedUpdates(() => {
setDescription(currentEditableFile.description);
setTitle(currentEditableFile.title);
setTags(currentEditableFile.tags);
});
}
}, [currentEditableFile]);
Related videos on Youtube
Vadim
Updated on April 13, 2022Comments
-
Vadim about 2 years
I have some side effects to apply in my react component and want to know how to organize them:
- as a single useEffect
- or several useEffects
Which is better in terms of performance and architecture?
-
AncientSwordRage over 2 yearsIt probably matters depending on your use case, but I'm going to edit your question to make it clear this is covering general advice.
-
ecoe almost 5 yearswhat about a middle ground between Second and Third example above?: you have logic that runs when a subset of state/props change, but each has separate logic that needs to run in addition to some common code that needs to run? You wouldn't use
[]
(because it's still only a subset of state/props you're awaiting changes for) but you'd also like to reuse code. Do you use separateuseEffects
and put the shared code in a function they each separately call? -
hakazvaka almost 5 yearsAs the answer below suggests, React team suggests separating hooks by concern, so you would split it into multiple
useEffect
calls. -
computrius about 4 yearsAre they always triggered in the order of their definition? i.e. effect1 is always called first, then effect2?
-
August Janse over 3 years@computrius Yes,
React will apply every effect used by the component, in the order they were specified.
-
Dror Bar over 3 yearsWhat if I have multiple "componentDidMount" effects (empty array []) but they do very different things? should I put them in a single useEffect or multiple?
-
AncientSwordRage over 2 yearscould you add some more of your code, to make it clear what bit of state
setTags
is updating? IssetTagsAdded
a function or object? Also how have you made sure 'performance and architecture' are better this way round vs. one big useEffect? -
AncientSwordRage over 2 yearsI know, but it would improve your answer if you explained why separation of concern, and whether that's an architectural or performance concept.
-
Bricky over 2 yearsI don't think including this code, especially out of context, is helpful or relevant to the question.
-
AncientSwordRage over 2 years@Bricky regardless, stripping out all the code AND adding in a quote changes the answer too much to justify it
-
Bricky over 2 yearsThe quote is the relevant section from the link. Simply including a link is a low-effort answer.