• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

在 useEffect 使用异步函数指南

武飞扬头像
夏安
帮助1

在 useEffect 中使用异步函数指南

useEffect 通常是 React 中进行数据获取的地方。数据获取意味着使用异步函数,在 useEffect 中使用它们可能不像你想象的那么简单。看完本文,你将会真正掌握在useEffect 中使用异步函数的正确姿态。

1. 错误方式

useEffect 中有一个错误的数据获取方法。如果你编写以下代码,你的 Linter 将向你发错警告:

// ❌ 不能这么做
useEffect(async () => {
  const data = await fetchData();
}, [fetchData])

这里的问题是 useEffect 的第一个参数应该是一个函数,它要么不返回任何东西(未定义),要么返回一个函数(以清除副作用)。但是 async 函数返回 Promise,它不能作为函数调用。这不是 useEffect hook 所期望的第一个参数。

那么如何在 useEffect 中使用异步代码呢?

2. 在 useEffect 中写入异步函数

通常解决方案是简单地在 useEffect 内部编写数据获取代码,像这样:

useEffect(() => {
  // 声明数据获取函数
  const fetchData = async () => {
    const data = await fetch('https://yourapi.com');
  }

  // 调用函数
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);
}, [])

需要注意的一点是,如果希望使用来自异步代码的结果,那么应该在 fetchData 函数内部而不是外部执行。例如,以下情况会导致问题:

useEffect(() => {
  // 声明异步数据获取函数
  const fetchData = async () => {
    // 从 API 获取数据
    const data = await fetch('https://yourapi.com');
    // 将数据转换为 json
    const json = await data.json();
    return json;
  }

  // 调用函数
  const result = fetchData()
    // 确保捕获任何错误
    .catch(console.error);

  // ❌ 不要这样做,它不会像你期望的那样运行
  setData(result);
}, [])
学新通

当调用 setData(result) 行时,你能猜出 result 变量是什么吗?

理解这一点的一种方法是编写一个只等待一定时间的异步函数。

useEffect(() => {
  // 声明异步数据获取函数
  const fetchData = async () => {
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    //等待 1000ms
    await sleep(1000);
    return 'Hello World';
  };

  const result = fetchData()
    // 确保捕获任何错误
    .catch(console.error);

  // 输出结果是什么?	
  console.log(result);
}, [])
学新通

输出结果是什么?

如果你答对了,恭喜你!result 将保存一个 pending 状态的 Promise 对象。在控制台中,你会看到如下内容:

Promise {<pending>}

那么如何在 useEffect 中使用异步代码的结果呢?答案是在获取数据函数内部。要修改上面的例子,你可以这样做:

useEffect(() => {
  // 声明异步数据获取函数
  const fetchData = async () => {
    // 从 API 获取数据
    const data = await fetch('https://yourapi.com');
    // 将数据转换为 json
    const json = await response.json();

    // 使用 result 设置状态 
    setData(json);
  }

  // 调用函数
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);;
}, [])
学新通

3. 如果需要从 useEffect 外部提取函数该怎么办?

在某些情况下,你希望在 useEffect 之外有数据获取函数。在这些情况下,你只需要小心地用 useCallback 包装函数。

为什么?因为函数是在 useEffect 之外声明的,所以必须把它放在 hook 的依赖数组中。但是如果函数没有被包装在 useCallback 中,它将在每次重新渲染时更新,从而在每次重新渲染时触发 useEffect。这不是我们想要的结果。

// 声明异步数据获取函数
const fetchData = useCallback(async () => {
  const data = await fetch('https://yourapi.com');

  setData(data);
}, [])

// useEffect 只在适当的时候调用 fetchData
useEffect(() => {
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);;
}, [fetchData])

在前面展示了一个在 useEffect 中获取数据的示例,有一个点需要注意:

useEffect(() => {
  // 声明异步数据获取函数
  const fetchData = async () => {
    // 从 API 获取数据
    const data = await fetch('https://yourapi.com');
    // 将数据转换为 json
    const json = await response.json();

    // 使用 result 设置状态 
    setData(json);
  }

  // 调用函数
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);;
}, [])
学新通

你通常需要一种能够取消 setData 调用的方法。在上面的例子中,它是没有用的,因为调用只执行了一次,但我们假设调用依赖于一个参数 param

useEffect(() => {
  // 声明异步数据获取函数
  const fetchData = async () => {
    // 从 API 获取数据
    const data = await fetch(`https://yourapi.com?param=${param}`);
    // 将数据转换为 json
    const json = await response.json();

    // 使用 result 设置状态 
    setData(json);
  }

  // 调用函数
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);;
}, [param])
学新通

如果 param 改变了值,fetchData 将被调用两次。如果这发生得很快,就有可能出现一个竞争条件,即第一个调用在第二个调用之后解决,因此状态将保持旧的值。

解决这个问题的方法是使用一个变量来控制是否更新状态。

useEffect(() => {
  let isSubscribed = true;

  // 声明异步数据获取函数
  const fetchData = async () => {
    // 从 API 获取数据
    const data = await fetch(`https://yourapi.com?param=${param}`);
    // 将数据转换为 json
    const json = await response.json();

    // 如果 'issubscriptions' 为 true,则用结果设置 state
    if (isSubscribed) {
      setData(json);
    }
  }

  // 调用函数
  fetchData()
    // 确保捕获任何错误
    .catch(console.error);;

  // 取消 setData
  return () => isSubscribed = false;
}, [param])
学新通

这是在可能多次触发 useEffect 中获取数据时非常常见的模式。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfiegbh
系列文章
更多 icon
同类精品
更多 icon
继续加载