51

In the useEffect function, if I just mention the getResults function variable, the app doesn't crash. But when I call it as I am doing in code below, I get these errors:

react-dom.development.js:21857 Uncaught TypeError: destroy is not a function

and

Consider adding an error boundary to your tree to customize error handling behavior.

  function App() {
  const [foods, setFoods] = useState([]);
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => getResponse());
  const getResponse = async () => {
    const response = await fetch(sampleRequest);
    const data = await response.json();
    setFoods(data.hits);
  };
  let query = "Tomato";
  let sampleRequest = `https://api.edamam.com/search?q=${query}&app_id=${"1811484f"}&app_key=${"9cac93361efc99e2ebfbb8a453882af8"}`;

  return (
    <div className="App">
      <div className="main">
        <div className="navbars">
          {" "}
          <Navbars></Navbars>
        </div>
        <div className="listings">
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
          <Listing></Listing>
        </div>
        <div className="footer">
          <h5>Made By YoYo Strangler in 2019</h5>
        </div>
      </div>
    </div>
  );
}

export default App;
peterh
  • 11,875
  • 18
  • 85
  • 108
Irakli Tchigladze
  • 693
  • 2
  • 7
  • 13

5 Answers5

76

You're returning the result of calling getResponse() from the useEffect function. If you return anything from useEffect, it has to be a function. Changing your code to this should fix it because you're no longer returning anything from the useEffect function.

useEffect(() => { 
  getResponse();
});

The useEffect Cleanup Function

If you return anything from the useEffect hook function, it must be a cleanup function. This function will run when the component unmounts. This can be thought of as roughly equivalent to the componentWillUnmount lifecycle method in class components.

useEffect(() => { 
  doSomething();

  return () => {
    console.log("This will be logged on unmount");
  }
});
Nick
  • 16,066
  • 3
  • 16
  • 32
  • thank you so much. It worked. So, essentially, two brackets {} around it made the difference? Can you give me keywords or phrases, which i can google and read more about this? – Irakli Tchigladze Oct 22 '19 at 09:04
  • 4
    @IrakliTchigladze yeah, “implicit return” of arrow functions. Also look up how useEffect works and what’s returned from it. Glad it worked! – Nick Oct 22 '19 at 11:27
  • @Nick Just a small correction: the cleanup function runs not only when component is unmounted, but also if one of the deps change (in such case it will run cleanup from the previous render) – Giorgi Moniava Jul 31 '22 at 16:36
  • Just to note, in case you have done some `await` calls you might have added `async` to userEffect, this also needs to be removed. – pjoshi Aug 13 '22 at 13:19
  • This solved my case too - ``` useEffect(() => { async function prepare() { // .. business logic }; prepare(); }, []) ``` – pjoshi Aug 13 '22 at 13:21
17

An async function is really just syntax sugar for promises, so when you call an async function, it's returning a promise.

Instead, you can wrap your async function with an IIFE (Immediately-invoked Function Expression) like this, so nothing is returned to useEffect and used as a cleanup function:

useEffect(() => { 
  (async () => getResponse())();
});

Edit: or as @json pointed out in comment below. Just:

useEffect(() => { getResponse() });
randomor
  • 5,329
  • 4
  • 46
  • 68
  • 3
    It's worth noting that while this solution does work, the IIFE has nothing to do with it, the braces around it suppress the implicit return value and that's what makes it work. – Jason Kohles Aug 17 '20 at 19:23
8

I used IIFE Like this, and it worked!!-

Previously it was this -

useEffect(async ()=>{
    const awesome_value = await AsyncStorage.getItem('awesome')
    setAwesome(awesome_value)
},[]);

Now I changed it to this -

useEffect( ()=>{
   (async() => {const awesome_value = await AsyncStorage.getItem('awesome')
   setAwesome(awesome_value)} ) ();
},[]);
Nikhil Jain
  • 244
  • 3
  • 7
2

The reason the simple code above is crashing your app is due to how the useEffect hook, async functions, and the shorthand arrow function syntax work.

One feature of the useEffect hook is a cleanup function. If you return anything from the useEffect hook function, it must be a cleanup function. This function will run when the component unmounts. This can be thought of as roughly equivalent to the componentWillUnmount lifecycle method in class components.

In JavaScript, functions marked with the async keyword enable the use of the await feature, which lets developers pause the execution of a function while waiting for an asynchronous task to finish. Async functions also always return a Promise; if the function doesn’t return one already, the return value is automatically wrapped in a Promise.

Finally, the shorthand arrow function syntax allows developers to omit the curly braces around the function body, which is useful for simple one-liners. The value of the function body automatically becomes the return value of the arrow function, removing the need of the return keyword. This functionality is called Implicit Return.

Now, how do these tidbits come together to cause such a cryptic error? Simply put, the value of getResponse, which is a Promise, becomes the return value of the arrow function in the useEffect hook. Remember that the useEffect hook expects a cleanup function to be returned? A Promise is not a function. so React stumbles and produces the error.

To fix your app, change the useEffect arrow function to add curly braces and remove the Implicit Return, as shown:

useEffect(() => { 
  getResponse();
});

Now, the arrow function in the useEffect hook returns undefined, which is acceptable and tells React that there is no cleanup function needed. This will solve the problem, but it would be great if React gave a more useful error message when this occurs!

aryanm
  • 1,183
  • 14
  • 26
0

Silly, but i had returned a response from my useEffect and i came up with this error. Please do check if you are also returning something from your effect.

Asad Ashraf
  • 1,425
  • 8
  • 19