DEV Community

Remon Fawzi
Remon Fawzi

Posted on • Edited on

Don't use useEffect unnecessarily

In this post We'll prove that in 90% of our components we don't need to write a useEffect ...

First question, When does useEffect run?

const User = ({name}) => { // 1
  const [initials, setInitials] = useState(""); // 2
  useEffect(() => {
    setInitials(name.split(" ").map(str => str.charAt(0))); // 4
  }, [name]);
  return (
    <p>{initials}</p> // 3
  );
};
Enter fullscreen mode Exit fullscreen mode

React will render this component in this sequence:

  1. Read the prop name, let's say it's value is "John Doe".
  2. Define the state called initials and give it the empty string as initial value.
  3. Return the JSX with this initial value, So initials will be an empty string.
  4. Run the function passed to the useEffect hook which sets the name to be "John Doe"
  5. Return the new JSX which now has initials as JD

So our component already had the value "John Doe" from beginning, But useEffect made it render twice! ... Let's get rid of this additional render ...

const User = ({name}) => { // 1
  const initials = name.split(" ").map(str => str.charAt(0)); // 2
  return (
    <p>{initials}</p> // 3
  );
};
Enter fullscreen mode Exit fullscreen mode

Now React will

  1. Read the value of name
  2. Calculate initials
  3. Return the JSX with the right value, Without the need of rendering the component again!

What if the previous component has more renders due to change in other props, It'll recalculate the initials in every new render, right? Yes, But instead of using a useEffect and putting the name in the dependency array ... We can easily use the useMemo hook not to recalculate the value with every new render!

const User = ({name, age, email}) => { // 1
  const initials = useMemo(() => {
    name.split(" ").map(str => str.charAt(0)); // 2
  }, [name]);
  return (
    <p>{initials}</p> // 3
  );
};
Enter fullscreen mode Exit fullscreen mode

Component will not recalculate initials when age or email changes!

So let's put this rule in our minds whenever We're creating a React component ...

Anything that could be calculated from props or state, Shouldn't be calculated inside a useEffect

We've all misused the useEffect hook to achieve things that could be easily achieved without using it and without the need of having additional renders which decrease page performance.

There's only one case in which you have to use useEffect, If you want to do something when component mounts (displayed for the first time), this thing is external (API fetch, subscribing to event, Applying something to a DOM element), Simply it's not depending on state or props ... So it'll be something like this

useEffect(() => {
    const fetchedPosts = fetch('....');
}, [])
Enter fullscreen mode Exit fullscreen mode

Conclusion

  • useEffect should be your last choice
  • useEffect runs after rendering your component, So if it makes any change to state, it'll cause additional renders
  • Anything that could be calculated from props or state, shouldn't be calculated inside a useEffect
  • You can use useMemo for expensive calculations
  • You can use useEffect only if you want to do something external (Ex: API fetch) when component mounts (First render only)

Thank u!

Top comments (13)

Collapse
 
eduardojm profile image
Eduardo Oliveira

The title of this article can be changed from "Don't use useEffect" to "Don't create dependent states on React"... useEffect should be used to handle side effects of some cases, like the useOutsideClick hook of the chakra-ui package.

Collapse
 
rem0nfawzi profile image
Remon Fawzi • Edited

Right, I just wanted to say We shouldn't use useEffect when what we want could be achieved without it.
Thank u!

Collapse
 
eduardojm profile image
Eduardo Oliveira

The wrong use of the useEffect is really a great problem in React (and i got some of it in legacy projects that i work :/)

Thread Thread
 
rem0nfawzi profile image
Remon Fawzi

We all did that 😅

Collapse
 
brense profile image
Rense Bakker

Indeed! If you need to set state based on changes in component state/props, you should use the useMemo hook. useEffect is only for triggering side effects outside of the scope of the component. Like adding event listeners to the window for example or interacting with a library that was not specifically written for React.

Collapse
 
rem0nfawzi profile image
Remon Fawzi

Exactly, Thank u!

Collapse
 
manuartero profile image
Manuel Artero Anguita 🟨

+100, useEffect() should only be used for fetch the initial data (and in some extreme extra situations)

useEffect(() => {
  api.fetchItems().....
}, [])
Enter fullscreen mode Exit fullscreen mode

good post!

Collapse
 
rem0nfawzi profile image
Remon Fawzi

Thank u!

Collapse
 
jagroop2001 profile image
Jagroop Singh

useEffect is very useful but it's Excessive use is very harmful in react project.

Collapse
 
rem0nfawzi profile image
Remon Fawzi

Yes exactly

Collapse
 
hpgriff profile image
Hp.Griff

Oh oh. I need to make some changes on my code... I'm using useEffect way too much. Thanks for the share !

Collapse
 
rem0nfawzi profile image
Remon Fawzi

You're welcome

Collapse
 
sanoshyadav979439 profile image
Santosh Yadav

You can use React.memo to not rerender the component itself in case of no prop change instead of useMsmo just for calculating initials