Avoid these 7 React useEffect Mistakes

Avoid these 7 React useEffect Mistakes
July 02, 2024

React's useEffect hook is a powerful tool for managing side effects in functional components, but it also comes with a set of common pitfalls that developers must be aware of.

Improper use of useEffect can lead to performance issues, bugs, and memory leaks - problems that can be difficult to diagnose and fix.

In this article, we'll explore the most frequent mistakes React developers make when working with useEffect, and provide clear, code-based examples of what to avoid and what to do instead.

By understanding the underlying principles and best practices for using useEffect, you'll be able to harness its full potential and build more robust, efficient, and maintainable React applications.

Whether you're a beginner or an experienced React developer, mastering the proper use of useEffect is a critical skill that will elevate your coding abilities.

1. Overusing effects

Sometimes, you don't need useEffect at all. If you're just computing a value based on props or state, do it directly in your component.

Avoid:

const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState('');


useEffect(() => {
  setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

Do:

const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = `${firstName} ${lastName}`;


2. Not cleaning up

If your effect sets up something like a subscription or timer, you need to clean it up to avoid memory leaks.

Avoid:

useEffect(() => {
  const timer = setInterval(() => {
    // do something
  }, 1000);
}, []);

Do:

useEffect(() => {
  const timer = setInterval(() => {
    // do something
  }, 1000);
  return () => clearInterval(timer);
}, []);


3. Using async functions directly

useEffect can't return a promise, so you can't use async functions directly.

Avoid:

useEffect(async () => {
  const response = await fetch('https://api.example.com');
  const data = await response.json();
  setData(data);
}, []);

Do:

useEffect(() => {
  const fetchData = async () => {
    const response = await fetch('https://api.example.com');
    const data = await response.json();
    setData(data);
  };
  fetchData();
}, []);


Are you looking for Front-end Developer Job? If yes, Click here to get interview kit and start preparing for your dream job.

4. Creating infinite loops

Be careful not to update a state that your effect depends on without a condition.

Avoid:

const [count, setCount] = useState(0);
useEffect(() => {
  setCount(count + 1);
}, [count]);

Do:

const [count, setCount] = useState(0);
useEffect(() => {
  if (count < 5) {
    setCount(count + 1);
  }
}, [count]);


5. Using objects or arrays as dependencies

React compares dependencies by reference, not value. Objects and arrays created in the component body will be different each render.

Avoid:

const user = { id: userId, name: userName };
useEffect(() => {
  // Effect using user
}, [user]); // This will run every render

Do:

useEffect(() => {
  //Effect using userId and userName directly
}, [userId, userName]);


6. Not memoizing callback functions

If you pass callbacks to child components, memoize them to prevent unnecessary re-renders.

Avoid:

const handleClick = () => {
  // handle click
};


useEffect(() => {
  document.addEventListener('click', handleClick);
  return () => document.removeEventListener('click', handleClick);
}, [handleClick]); // This will run every render

Do:

const handleClick = useCallback(() => {
  //handle click
}, []);


useEffect(() => {
  document.addEventListener('click', handleClick);
  return () => document.removeEventListener('click', handleClick);
}, [handleClick]); //This will only run when handleClick changes


Are you looking for Front-end Developer Job? If yes, Click here to get interview kit and start preparing for your dream job.

7. Using useEffect for data fetching without considering race conditions

If you fetch data in useEffect, make sure to handle cases where the component unmounts before the fetch completes.

Avoid:

useEffect(() => {
  let isMounted = true;
  fetchData().then(data => {
    setData(data);
  });
}, []);

Do:

useEffect(() => {
  let isMounted = true;
  fetchData().then(data => {
    if (isMounted) {
      setData(data);
    }
  });
  return () => {
    isMounted = false;
  };
}, []);



Resources for You

ChatGPT Guide For Software Developers

Learn to use ChatGPT to stay ahead of competition

Front-End Developer Interview Kit

Today, Start preparing to get your dream job!

JavaScript Developer Kit

Start your JavaScript journey today!

Newsletter for Developers!

Join our newsletter to get important Web Development and Technology Updates