如何让useEffet支持async/await

前言

刚开始学react写过类似下面的代码,就是想直接在useEffect中使用async/await。然后浏览器就会报错如下图:

useEffect(async () => {
    const res = await Promise.resolve({ code: 200, mes: '' });
  }, [])

如何让useEffet支持async/await_第1张图片
报错的意思: useEffect 期望接受一个同步的函数作为参数,但 async 函数实际上返回的是一个 Promise。useEffect应该返回的是一个销毁函数,这里第一个参数使用了async,返回就是promise,会导致销毁函数报错。

react为什么这么做

我们都知道useEffect是很重要的一个hooks,可以执行一些副作用操作,它可以完成一些在class组件中一些生命周期函数的职责。如果返回值是异步的,那我们可能就无法预知代码的执行情况,很容易出现难以定位的bug,所以React就直接限制了useEffec回调函数中不支持async/await。

useEffect期望一个函数,而async () => {}返回的是一个Promise。这样的使用会造成不匹配,因为useEffect不支持直接返回Promise,它需要一个函数,且该函数可以返回另一个函数用于清理。

这就是为什么像useEffect(async () => {}, [])这样的用法会导致错误。JavaScript引擎会指出传递给useEffect的参数不符合其要求。

useEffect如何支持async/await

方式一:
可以在useEffect内部定义一个async函数,然后在其中使用async/await语法来处理异步操作。

useEffect(() => {
  const fetchData = async () => {
    try {
      const result = await someAsyncOperation();
      // 进行其他操作,比如更新 state
    } catch (error) {
      // 处理错误
    }
  };

  fetchData();

  // 你可以选择返回一个清除函数,如果需要清理操作的话
  return () => {
    // 清理操作
  };
}, [/* 依赖 */]);

注意,在useEffect内部定义一个async函数并不会改变useEffect的行为,它仍然会被当做同步操作处理。这里,我们只是利用了async/await语法来处理异步操作,但useEffect本身仍需遵循其原有的规则和生命周期。
方式二:
你可以直接在 useEffect 中使用 IIFE(立即调用函数表达式)来处理异步操作。这种方法可以让你在 useEffect 中立即执行异步函数。

useEffect(() => {
  (async () => {
    try {
      const result = await someAsyncOperation();
      // 处理结果
    } catch (error) {
      // 处理错误
    }
  })();

  // 可选:返回一个清理函数
  return () => {
    // 清理操作
  };
}, [/* 依赖 */]);

自定义useAsyncEffect 函数

当涉及到在useEffect中使用异步操作时,可以创建自定义的useAsyncEffect钩子函数,返回一个清理函数,类似于内置的useEffect。在异步操作结束后执行清理操作,这个自定义钩子可以管理异步逻辑并使其更清晰易用。

const useAsyncEffect = (effectFunction, cleanupFunction, dependencies) => {
  useEffect(() => {
    effectFunction();
    return cleanupFunction;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, dependencies);
};

这样的话可以在调用 useAsyncEffect 时传入异步函数、清理函数和依赖项数组。在内部使用 useEffect,并确保在 useEffect 中返回清理函数,以便在组件卸载或依赖项变更时执行清理操作。

使用:

useAsyncEffect(
  async () => {
    try {
      const result = await fetchData();
      // 处理获取的数据
    } catch (error) {
      // 处理错误
    }
  },
  () => {
    // 执行清理操作
  },
  [/* dependencies */]
);

这种方式能够在传入异步操作和清理函数的同时,仍然利用 useEffect 的特性进行管理。
这useAsyncEffect只是一个简单的自定义封装,使用还需对useEffect内部逻辑的理解。

你可能感兴趣的:(javascript,前端,useEffect,react)