Common mistakes while fetching in useEffect

Fetching data in React components is a common operation, and the useEffect hook plays a crucial role in managing asynchronous tasks.

Let's see some common mistakes while fetching data in useEffect and also learn the best practices to avoid them.

Not cleaning up the effect

Not cleaning up the effect can lead to memory leaks. For example, let's say you want to subscribe to a data source

// This effect runs after every render
useEffect(() => {
  const subscription = dataSource.subscribe()
})

Make sure to unsubscribe from the data source when the component unmounts

useEffect(() => {
  const subscription = dataSource.subscribe()
  return () => {
    subscription.unsubscribe()
  }
})

Forgetting the dependency array

useEffect runs on every render by default. This can lead to performance issues. For example, let's say you want to subscribe to a data source but the data is static and won't change based on props or state.

const [data, setData] = useState(null)

useEffect(() => {
  const fetchData = async () => {
    const data = await fetch('https://api.example.com/data')
    setData(data)
  }
})

This is a easily avoidable mistake. To fix it, we need to pass an empty array as the second argument to useEffect. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.

const [data, setData] = useState(null)

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

Not including all dependencies in the dependency array cause stale data

Adding unnecessary dependencies to the dependency array can also lead to bugs. For example, let's say you want to fetch data from an API based on a prop.

const [data, setData] = useState(null)

useEffect(() => {
  const fetchData = async () => {
    const data = await fetch(`https://api.example.com/data/${props.id}`)
    setData(data)
  }
}, [])

This is another common mistake. To fix it, we need to add the prop to the dependency array.

const [data, setData] = useState(null)

useEffect(() => {
  const fetchData = async () => {
    const data = await fetch(`https://api.example.com/data/${props.id}`)
    setData(data)
  }
}, [props.id])

Conditional fetching without dependencies

One other variant of same dependency array mistake is conditional fetching without dependencies. For example,

// Incorrect
let shouldFetch = true

useEffect(() => {
  if (shouldFetch) {
    fetchData()
  }
}, [])

// Correct
let shouldFetch = true

useEffect(() => {
  if (shouldFetch) {
    fetchData()
  }
}, [shouldFetch])

Not using useCallback or causing infinite loops

useCallback is a hook that returns a memoized callback. It's useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

For example, let's say you have a component that fetches data from an API and renders it.

const [data, setData] = useState(null)

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

return <div>{data}</div>

Now, let's say you want to pass the fetchData function to a child component. You can't just pass the fetchData function directly because it will be recreated on every render. This will cause the child component to re-render unnecessarily.

const [data, setData] = useState(null)

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

return <ChildComponent fetchData={fetchData} />

To fix this, you need to wrap the fetchData function in useCallback.

const [data, setData] = useState(null)

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

useEffect(() => {
  fetchData()
}, [fetchData])

return <ChildComponent fetchData={fetchData} />

Hope it helps to learn few different variant of mistakes while fetching data in useEffect.

Keep learning and share your comments by tagging me on twitter @learnwithparam 🙌

🔥 Limited Time Offer
Coding with AI: Learn to build a SaaS MVP in 10 days

Coding with AI: Learn to build a SaaS MVP in 10 days

Master practical AI development to build and launch your startup MVP in weeks instead of months. Learn to leverage AI tools and APIs effectively.

  • 🎯 Build real MVP: AI-powered SaaS from idea to launch
  • 🤖 Integrate ChatGPT, Claude, and other AI APIs efficiently
  • 💰 Implement AI features users will pay for
  • ⚡️ AI-assisted coding patterns to ship 10x faster
  • 🚀 Launch your product in 10 days, not 10 months