'react-hooks/exhaustive-deps warning--unclear about course of action

I am getting these lint errors

./components/create-nft/InstagramSelector.js
39:15  Warning: Effect callbacks are synchronous to prevent race conditions. Put the async function inside:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching  react-hooks/exhaustive-deps

If I look at line 39, it begins with this:

    useEffect(async () => {
        console.log("on mount")

        if (localStorageApi.isLoggedInIg()) {
            setLoggedIn(true)
        }
        else {
            setLoggedIn(false)
        }

    }, [])

localStorageApi, is just a wrapper around localStorage, which is synchronous. setLoggedIn, is the useState setter

next is this warning:

56:8  Warning: React Hook useEffect has a missing dependency: 'getIgMedia'. Either include it or remove the dependency array.  react-hooks/exhaustive-deps

Line 56 is the last line here:

    useEffect(() => {
        if (loggedIn) {
            (async () => await getIgMedia())()
        }
        
    }, [loggedIn])

I don't understand what I am supposed to do here. I want the function to trigger when there is a change with "loggedIn". I don't want it to trigger with any other dependency.



Solution 1:[1]

If I am understanding your post correctly, you have React hook warnings with 2 useEffect hooks you are using.

  1. Warning: Effect callbacks are synchronous to prevent race conditions.

    useEffect(async () => {
      console.log("on mount");
    
      if (localStorageApi.isLoggedInIg()) {
        setLoggedIn(true);
      } else {
        setLoggedIn(false);
      }
    }, []);
    

    The issue here, and what the warning is pointing out, is that React hook callbacks are synchronous functions. You've passed an async function. async functions implicitly return a Promise, which can cause issues when React assumes, incorrectly, that this returned value is a cleanup function.

    Normally you would declare the async function inside the callback and invoke it, e.g.

    useEffect(() => {
      const getLoggedInState = async () => {
        console.log("on mount");
        setLoggedIn(localStorageApi.isLoggedInIg());
      };
    
      getLoggedInState();
    }, []);
    

    but since there's not actually any asynchronous code and no use of await there is no need for the function to be declared async, e.g.

    useEffect(() => {
      console.log("on mount");
      setLoggedIn(localStorageApi.isLoggedInIg());
    }, []);
    
  2. Warning: React Hook useEffect has a missing dependency: 'getIgMedia'.

    useEffect(() => {
      if (loggedIn) {
        (async () => await getIgMedia())();
      } 
    }, [loggedIn]);
    

    The issue here is that getIgMedia is declared outside the useEffect hook's callback and referenced inside it. This makes it a dependency.

    You can either move the getIgMedia function declaration into the hook (just like was done above with the first useEffect hook) to remove it as an external dependency.

    useEffect(() => {
      const getIgMedia = () => { ... };
    
      if (loggedIn) {
        (async () => await getIgMedia())();
      } 
    }, [loggedIn]);
    

    Or add it to the dependency array.

    useEffect(() => {
      if (loggedIn) {
        (async () => await getIgMedia())();
      } 
    }, [getIgMedia, loggedIn]);
    

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1