将异步函数放入 useEffect 后出现错误

Posted

技术标签:

【中文标题】将异步函数放入 useEffect 后出现错误【英文标题】:Getting error after I put Async function in useEffect 【发布时间】:2020-02-18 01:42:02 【问题描述】:

在 useEffect 函数中,如果我只提到 getResults 函数变量,应用程序不会崩溃。但是当我在下面的代码中调用它时,我得到了这些错误:

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

考虑在树中添加错误边界以自​​定义错误处理行为。

  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;

【问题讨论】:

【参考方案1】:

您正在返回从useEffect 函数调用getResponse() 的结果。如果你从useEffect 返回任何东西,它必须是一个函数。将您的代码更改为此应该可以解决它,因为您不再从 useEffect 函数返回任何内容。

useEffect(() =>  
  getResponse();
);

useEffect 清理函数

如果您从useEffect 挂钩函数返回任何内容,则它必须是清理函数。此函数将在组件卸载时运行。这可以认为大致相当于类组件中的componentWillUnmount生命周期方法。

useEffect(() =>  
  doSomething();

  return () => 
    console.log("This will be logged on unmount");
  
);

【讨论】:

非常感谢。有效。所以,本质上,它周围的两个括号 有区别吗?你能给我关键字或短语,我可以用谷歌搜索并阅读更多相关信息吗? @IrakliTchigladze 是的,箭头函数的“隐式返回”。还要查看 useEffect 的工作原理以及从中返回的内容。很高兴它成功了!【参考方案2】:

异步函数实际上只是 Promise 的语法糖,所以当您调用异步函数时,它会返回一个 Promise。

相反,您可以使用这样的 IIFE(立即调用函数表达式)包装您的异步函数,因此不会返回任何内容到 useEffect 并用作清理函数:

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

编辑:或者正如@json 在下面的评论中指出的那样。只是:

useEffect(() =>  getResponse() );

【讨论】:

值得注意的是,虽然这个解决方案确实有效,但 IIFE 与它无关,它周围的大括号抑制了隐式返回值,这就是它起作用的原因。【参考方案3】:

上面的简单代码导致您的应用崩溃的原因是 useEffect 钩子、async 函数和速记箭头函数语法的工作方式。

useEffect 挂钩的一个特性是清理功能。如果你从 useEffect 钩子函数返回任何东西,它必须是一个清理函数。此函数将在组件卸载时运行。这可以认为大致相当于类组件中的 componentWillUnmount 生命周期方法。

javascript 中,标有 async 关键字的函数可以使用 await 特性,它允许开发人员在等待异步任务完成时暂停函数的执行。异步函数也总是返回一个 Promise;如果函数还没有返回一个,则返回值会自动包装在 Promise 中。

最后,速记箭头函数语法允许开发人员省略函数体周围的花括号,这对于简单的单行语句很有用。函数体的值自动成为箭头函数的返回值,不再需要return关键字。此功能称为隐式返回。

现在,这些花絮是如何聚集在一起导致如此神秘的错误的?简单来说,getResponse 的值,也就是一个 Promise,变成了 useEffect 钩子中箭头函数的返回值。还记得 useEffect 钩子期望返回一个清理函数吗? Promise 不是函数。所以 React 会出错并产生错误。

要修复您的应用,请更改 useEffect 箭头函数以添加花括号并删除隐式返回,如图所示:

useEffect(() =>  
  getResponse();
);

现在,useEffect 钩子中的箭头函数返回undefined,这是可以接受的,并告诉 React 不需要清理函数。这将解决问题,但如果 R​​eact 在发生这种情况时给出更有用的错误消息,那就太好了!

【讨论】:

【参考方案4】:

我就这样用过 IIFE,而且效果很好!!-

以前是这样的-

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

现在我把它改成了这个-

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

【讨论】:

以上是关于将异步函数放入 useEffect 后出现错误的主要内容,如果未能解决你的问题,请参考以下文章

Next.js 500 内部服务器错误在 404 页面内调用 useEffect Hook 后立即出现

如何在 React 的 UseEffect() 中调用异步函数?

如何取消 useEffect 清理函数中的所有订阅和异步任务?

React 中带有 useEffect 的异步上下文

useState 在 useEffect 中定义后保持初始状态

异步等待不等待 useEffect 内的响应