【问题标题】:Add Async/Await to React Fetch Request添加 Async/Await 以响应获取请求
【发布时间】:2021-05-20 19:02:43
【问题描述】:

我正在向这个 API 发出一个获取请求,并且我成功地获取了数据并将其打印到控制台。但是,我对 Javascript/React 中的异步调用不熟悉。如何在此代码中添加 async/await 以在成功获取时延迟渲染?我得到了经典的Uncaught (in promise) TypeError: Cannot read property '0' of undefined,因为我相信 DOM 正在尝试渲染尚未完全获取的数据。

import React, { useEffect, useState } from "react";

export default function News() {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [stories, setStory] = useState([]);

  useEffect(() => {
    fetch(
      "http://api.mediastack.com/v1/news"
    )
      .then((res) => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setStory(result);
          console.log(result.data[0]);       // printing to console to test response
          console.log(result.data[0].title); // printing to console to test response
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!isLoaded) {
    return <div>Loading...</div>;
  } else {
    return (
      <div>
        <p>{stories.data[0].title} </p> // this is the where render error is
      </div>
    );
  }
}

【问题讨论】:

  • 您要发送 API 访问密钥吗?
  • 是的,我是,但我为这篇文章删除了它,因为它对我来说是私人的。这不是最佳做法吗?不公开分享这些东西?
  • 也许你可以让你的函数异步,然后用 await 调用它。
  • 这正是我要寻求帮助的。我知道我需要 async/await 但无法正确实现。
  • 尝试将setStory(result);放在setIsLoaded(true);之前

标签: javascript reactjs asynchronous async-await fetch


【解决方案1】:

问题是您的isLoaded 状态变量在stories 之前更新,尽管您首先设置了前一个状态。以下是解决此问题的方法:

import { useEffect, useState } from "react";

export default function App() {
  const [error, setError] = useState(null);
  const [stories, setStory] = useState(null);

  useEffect(() => {
    fetch("your_url")
      .then((res) => return res.json())
      .then((result) => {
        setStory(result);
        console.log("Success ", result);
      })
      .catch((error) => {
        console.log("Error", error);
      });
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!stories) {
    return <div>Loading...</div>;
  } else {
    return (
      <div>
        <p>stories.data[0].title} </p>
      </div>
    );
  }
}

完全摆脱 isLoaded 变量并使用 stories 变量表示它正在加载。

如果您想为您的 api 调用添加人工加载时间。你可以这样做:

  useEffect(() => {
    fetch("your_url")
      .then((res) => return res.json())
      .then((result) => {
        setTimeout(() => setStory(result), 2000)
      })
      .catch((error) => {
        console.log("Error", error);
      });
  }, []);

这将在设置状态之前增加 2 秒,从而让您看到加载器的样子。

【讨论】:

    【解决方案2】:

    async/await 只是检索异步数据的另一种形式,就像您在 then 中所做的那样。

    消息:

     Cannot read property '0' of undefined
    

    表示“result.data”未定义。

    不管怎样,如果它进入了“then”回调,则总是意味着请求被抓取,没有“半抓取”或“完全抓取”之类的东西。

    我建议你使用调试器,通过放置

    debugger;
    

    就在“then”回调的开头,以确保您的结果是什么。 或者你也可以 console.log 结果。

    澄清一下:

    myFunctionThatReturnsPromise.then(response => //do something with response)
    

    相同
    await response = myFunctionThatReturnsPromise;
    

    您可以考虑使用 stories?.data?.[0]?.title 来解决此问题。

    【讨论】:

    • 我知道它已获取数据,因为它出现在我的控制台中。但是,我需要帮助编写 async/await 部分,因为它正在尝试使用尚不存在的数据呈现

      标记。

    • 如果你使用问号运算符,比如:story?.data?.[0]?.title
    【解决方案3】:

    您的错误不会随着 async await 而消失,因为您正在调用一个没有值的嵌套空对象。 react 中的 render 方法在你使用的 useEffect 之前。您可以使用两种解决方案:

    1.使用可选的链接 es20 功能,如下所示:

    &lt;p&gt;{stories?.data?.[0]?.title} &lt;/p&gt; 

    2.在p标签前使用嵌套if语句判断是否有数据:

    似乎第一个选项更干净

    【讨论】:

      【解决方案4】:

      您已经有使用 Promise.then 的异步代码,所以 async/await 在这里无法帮助您 - 它只是编写基于 Promise 的功能的另一种方式。

      您的问题正如您所说 - React 正在尝试在 stories 有任何内容供您渲染之前渲染您的 else 块。我认为您只需要编写更严格的条件,例如

        if (error) {
          return <div>Error: {error.message}</div>;
        }
      
        if (!isLoaded || !stories.data.length) {
          return <div>Loading...</div>;
        }
        
        return (
          <div>
            <p>{stories.data[0].title} </p> // this is the where render error is
          </div>
        );
      

      【讨论】:

        猜你喜欢
        • 2018-09-14
        • 1970-01-01
        • 1970-01-01
        • 2018-02-09
        • 2018-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多