React useEffect Hook Tips

  • August 11, 2022
  • 2 min read

Things to be careful when using useEffect

  1. always specify a dep array
  2. beware of array, objects as dependancy

Tips

1. Making API requests -- The better way of using useEffect

// handle component mount & unmount
useEffect(() => {
  let mounted = true;
  getList().then((items) => {
    if (mounted) {
      setList(items);
    }
  });
  // onUnmount cancel the request
  return () => (mounted = false);
}, []);

Above solution will not work for handleSubmit, since it is not an effect. You can’t return a function to set the value to false when it is unmounted. Further, it would be inefficient to add the same check to every function

So better solution would be useRef. The useRef Hook will preserve a variable for the lifetime of the component.

const mounted = useRef(true);

useEffect(() => {
  mounted.current = true;
  if (list.length && !alert) {
    return;
  }
  getList().then((items) => {
    if (mounted.current) {
      setList(items);
    }
  });
  return () => (mounted.current = false);
}, []);

so using this let's make a data fetching hook:

import React, { useState, useEffect, useRef, useLayoutEffect } from "react";

const useCallbackRef = (callback) => {
const callbackRef = useRef(callback);
// synchronous vairant useEffect
useLayoutEffect(() => {
  callbackRef.current = callback;
}, [callback]);
return callbackRef;
};

const mounted = useRef(true);

export const useFetch = (options) => {
const [data, setData] = useState(null);
const savedOnSuccess = useCallbackRef(options.onSuccess);

useEffect(() => {
  if (options.url) {
    let mounted.current = false;
    fetch(options.url)
      .then((response) => response.json())
      .then((json) => {
        if (mount.current) {
          savedOnSuccess.current?.(json);
          setData(json);
        }
      });
    return () => mounted.current = false
  }
}, [options.url]);

return {
  data,
};
};

We can use hooks like useSWR https://github.com/vercel/swr to make API calls that eliminate above issues and add functionalities like caching

2. Use Effect with setInterval

Depending On State Mutated In The useEffect

const [number, setNumber] = useState(0);
useEffect(() => {
  setInterval(() => {
    // use Update function of setState
    setNumber((prev) => prev + 1);
  }, 1000);
}, []);