# 解析React useEffect不支持async function示例

> 作者/来源: UCloud 运营管理员
> 发布时间: 2022-11-17T14:08:00.000Z
> 分类: AI专区
> 标签: AI
> 原文链接: http://117.50.162.249:3000/yun/articles/2113

---

# 解析React useEffect不支持async function示例

> 来源: https://www.ucloud.cn/yun/128370.html
> 作者: 3403771864
> 发布日期: 发布于2022-11-17 22:08

useEffect是很常见的，现在写的是十分需求的。

```
　　useEffect(async()=>{ 
　　awaitgetPoiInfo();//请求数据
　　 },[]);
```

　　可是React 却无法支持这样做，就是因为 effect function 应该返回一个销毁函数（effect：是指return返回的cleanup函数），如果 useEffect 第一个参数传入 async，返回值则变成了 Promise，会导致 react 在调用销毁函数的时候报错 ：function.apply is undefined。

　　React为什么这么设计呢？

　　1、useEffect 的返回值是要在卸载组件时调用的，React 需要在 mount 的这样才可以获取值。

　　2、useEffect() 似乎有个潜在逻辑：第二次触发 useEffect 里的回调前，前一次触发的行为都执行完成，返回的清理函数也执行完成。这样逻辑才清楚。而如果是异步的，情况会变得很复杂，可能会很容易写出有 bug 的代码。

　　下面有两种改进的方法大家可以参考下：

　　简单改造

　　1、简单改造的写法（不推荐）

　　第一种 在内部创建一个异步函数anyNameFunction，之后就是等待，在后来就是调用setData

　　可也有一个问题要知道，就是在asyncFunction请求有依赖外部的参数，不更新requestData 的 effect 的依赖，effect 就不会同步 props 和 state 带来的变更，也就不回重新请求数据

```
　　useEffect(() => {
　　// Create an scoped async function in the hook
　　// 注意如果函数没有使用组件内的任何值，可以把它提到组件外面去定义
　　// 下面代码可以提到外面，可以自由地在 effect 中使用，下面就不改啦
　　async function asyncFunction() {
　　await requestData();
　　setData(data)
　　}
　　// Execute the created function directly
　　anyNameFunction();
　　}, []); // 这里设置成[]数组，因为我们只想在挂载的时候运行它一次
```

　　或者 useEffect中异步函数采用IIFE写法（ Immediately Invoked Function Expression即立即调用的函数式表达式）

```
　　useEffect(() => {
　　// Using an IIFE
　　(async function anyNameFunction() {
　　await requestData();
　　})();
　　}, []);
```

　　2、把异步提取成多带带函数或自定义hook（推荐）

　　第一种自定义 hook包裹，然后再effect中通过promise.then调用（github上大佬给的答案：github）

```
　　// 自定义hook
　　function useAsyncEffect(effect: () => Promise<void | (() => void)>, dependencies?: any[]) {
　　return useEffect(() => {
　　const cleanupPromise = effect()
　　return () => { cleanupPromise.then(cleanup => cleanup && cleanup()) }
　　}, dependencies)
　　}
　　// 使用
　　useAsyncEffect(async () => {
　　const count = await fetchData()
　　setCount(count)
　　}, [fetchData])
```

　　或者利用useCallback 包装成hook

　　useCallback 本质上是添加了一层依赖检查，使用useCallback，函数完全可以参与到数据流中，可以说如果一个函数的输入改变了，这个函数就改变了，如果没有，函数也不会改变。

　　下面的例子中会依赖 type ，如果 type 保持不变，requestData 也会保持不变，effect 也不会重新运行，但是如果 type 修改了，requestData 也会随之改变，因此会重新请求数据。

```
　// 封装
　　const requestData = useCallback(async () => {
　　changeLoading(true);
　　changeError(false);
　　changeList([]);
　　requestAPI.getFeature({ type }).then((data) => {
　　if (data) {
　　changeList(data);
　　}
　　}).catch((e) => {
　　changeError(true);
　　}).finally(() => {
　　changeLoading(false);
　　});
　　}, [type]); // type改变会重新生成函数
　　// 普通接口请求
　　useEffect(() => {
　　requestData();
　　}, [requestData]);
　　// 多带带处理外层刷新的接口请求
　　// refreshing是props传递的过来的，不应该与state状态改变混在一起，这也是hook的优势，将不相关的状态逻辑拆分成更细粒度
　　useEffect(() => {
　　if (!refreshing) {
　　return;
　　}
　　requestData().then(() => {
　　getRefreshStatus(false);
　　});
　　}, [refreshing]);
```

　　今天讲到这里，后面更多精彩内容欢迎观看。