React Hooks学习之在useEffect实现异步


关于React Hooks最开始是看了阮一峰老师的《React Hooks 入门教程》,里面非常精准地讲了常用的hooks的基本使用,感觉hooks真的是非常方便。本文主要探究useEffect中的异步用法。

useEffect(()  =>  {
  // Async Action
}, [dependencies])

其实useEffect就相当于原生React中的componentDidMount,用来引入具有副作用的操作,最常见的就是向服务器请求数据。在请求数据的过程中往往需要进行异步操作,如何在useEffect中使用异步函数呢?

问题描述

在界面加载的时候,我希望异步请求数据,最初按照我个人对useEffect的使用理解,我这样实现的:

const MyComponent: React.FC = props => {
  const [data, setData] = this.useState('');
  
  useEffect(async () => {
    const data = await loadContent();
    setData(data);
  }, []);
  
  return 
{data}
; }

但是在跳转路由(离开当前界面)的时候会遇到如下错误 ❌
TypeError: func.apply is not a function

问题分析

看了下Github上的讨论区🙌🏻TypeError: func.apply is not a function / Uncaught TypeError: destroy is not a function,很多人也遇到了这个问题,有个高赞的评论是这样解析的:‘ you’re returning a value from useEffect that isn’t a function’ ,真实报错原因是——如此使用异步函数导致我们在使用useEffect()的时候返回的是一个值而非函数。
原因及解决方法
也就是说我们在使用useEffect(()=>{},[])时,需要将async或者Promise异步函数单独拎出来写,然后在effect内部的第一个参数中调用这个异步函数。

🤔️🤔️🤔️究竟为什么会这样呢?

回顾下异步函数的定义:

A function that allows to use asynchronous instructions with the await keyword which will block the statement execution as long as the Promise after which the await keyword is doesn’t resolve…
This function will also return a Promise, no matter if you explicitly return something or not. In case you return data, it will be wrapped in the resolving content of the promise that the function will create and return automatically.

大致意思是异步函数允许将异步指令与await关键字一起使用的函数,只要不解决await关键字之后的Promise,它将阻止语句执行…
但是下面这句却表明,无论您是否明确返回某些内容,此函数都会返回一个Promise。万一你返回数据,它将包装在Promise的解决内容中,自动创建并返回。

而反观useEffect hooks官方文档的描述:

Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID. To do this, the function passed to useEffect may return a clean-up function. For example, to create a subscription.

通常,effects需要在组件离开屏幕之前清除创建的资源,例如订阅或计时器ID。为此,传递给useEffect的函数应该返回一个清理函数。

原因已经十分清楚了,原本需要返回的是一个cleanup函数,而使用异步函数会使callback返回Promise而不是cleanup函数,也就不难解释为何当我离开界面的时候,才遇到报错的情况。

问题解决

针对如何使用异步,上面其实也已经说过了,主要解决思路就是避免直接将Promise作为返回,把异步函数独立出来,可以像上面一样在useEffect外部写一个函数内部调用,也可以直接在useEffect内部封装一个内部函数,然后调用。

const MyComponent: React.FC = props => {
  const [data, setData] = this.useState('');
  
  useEffect(() => {
    async getData () {
      return await loadContent();
    }
    const data  = getData();
    setData(data);
  }, []);
  
  return 
{data}
; }

当然亦可以使用IIFE( Immediately Invoked Function Expression),即使用一个匿名函数表达式,适合没有返回数据的异步情况

const MyComponent: React.FC = props => {
  // IIFE
  useEffect(() => {
    (async function updateData(){
      await updateContent();
    })();
  }, []);
  
  return 
; }

🌟最后附上《一份完整的useEffect使用指南》,感觉蛮细致,值得学习借鉴


Author: Casey Lu
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Casey Lu !
评论
 Previous
yarn的安装及指令 yarn的安装及指令
像npm一样,yarn是由Facebook发布的一款取代npm的包管理工具。 一、yarn的安装 安装前提: node.js, 安装 npm install -g yarn yarn 淘宝源安装 yarn config set reg
2020-05-16
Next 
四月天的一纸絮叨 四月天的一纸絮叨
这一个月的时间真心是飞速,回顾了三月底的flag,我觉得还算是满意的,至少没有让自己失望,感觉充实无比~吼吼吼 小有成长,空间辽阔 这个月算是一个过渡的月份,从学习状态到开发状态的切换,投身到真实的项目开发中,节奏比我想象中的要快,但是自己
2020-04-30
  TOC