在反应中使用 async/await 未定义

Posted

技术标签:

【中文标题】在反应中使用 async/await 未定义【英文标题】:undefined using async/await in react 【发布时间】:2021-02-17 21:33:52 【问题描述】:

我正在尝试使用 github api 来获取用户的项目并在弹出窗口中列出它们。我无法弄清楚为什么 async / await 不起作用并且我最终传递的数据始终未定义。

这就是我从 api 获取数据的方式(已编辑用于...):

export default async function GitHubFetch( userName ) 
  let returnArray = [];
  let response = await customFetch(
    Urls.GitHub + "users/" + userName + "/repos"
  );

  for (const element of response) 
    let project = ;
    project.name = element.name;
    project.description = element.description;
    project.html_url = element.html_url;

    let langResponse = await customFetch(element.languages_url);
    project.languages = Object.keys(langResponse);
    returnArray.push(project);
  
  console.log("the array i'm returning from fetch is: ", returnArray);
  return returnArray;

这个函数的returnArray的console.log是:

["name":"cthulu_finance","description":"stock-trading application written in react and node.js / express","html_url":"https://github.com/contip/cthulu_finance","languages":["TypeScript","HTML","CSS"],"name":"c_structures","description":"collection of data structures in c","html_url":"https://github.com/contip/c_structures","languages":["C"],"name":"masm_io_procedures","description":"Low-level implementations of string-to-int and int-to-string in x86 assembly","html_url":"https://github.com/contip/masm_io_procedures","languages":["Assembly"]]

上述函数中的项目数组用于生成项目列表:

export default function GitHubListDisplay( projects ) 
  let listItems = [];
  console.log(projects);
  if (Array.isArray(projects)) 
    projects.forEach((project, index) => 
      listItems.push(
        <>
          <ListGroup.Item action href=project.html_url>
            project.name
          </ListGroup.Item>
          <ListGroup.Item>project.description</ListGroup.Item>
          <ListGroup horizontal>HorizontalList(project.languages)</ListGroup>
        </>
      );
    );
  
  return <ListGroup>listItems</ListGroup>;

最后,这一切都由这个函数控制:

export default function GitHubPopUp( userName ) 
  const [projectData, setProjectData] = useState([]);

  useEffect(() => 
    async function fetchData() 
      setProjectData(await GitHubFetch( userName ));
      console.log("the project data i fetched is: ", projectData);
    
    fetchData();
  , []);

  return (
    <>
      <OverlayTrigger
        placement="right"
        delay= show: 250, hide: 5000 
        overlay=
          <Popover>
            <Popover.Title as="h3">`GitHub Projects`</Popover.Title>
            <Popover.Content>
              <strong>userName's GitHub Projects:</strong>
              projectData.length > 0 && (
                <GitHubListDisplay ...projectData />
              )
            </Popover.Content>
          </Popover>
        
      >
        <Button variant="link">userName</Button>
      </OverlayTrigger>
    </>
  );

从主控制器功能,状态最终得到正确设置,但如果我在等待 Fetch 功能结果后直接控制台记录 projectData 状态,它是未定义的.. 结果是:

the project data i fetched is:  []

此外,即使我有 projectData.length &gt; 0 &amp;&amp; 在渲染 GitHubListDisplay 组件之前,console.logging 输入 projects 属性总是导致未定义。该函数永远不会显示任何内容。

有人可以帮忙吗?我花了令人尴尬的时间试图弄清楚这一点。

【问题讨论】:

forEach 内部使用的 'await' 永远不会阻塞主线程并执行 return 语句。所以你的 'GitHubFetch' 函数总是返回一个空数组。使用威廉指出的 promise.all()。 【参考方案1】:

export default function GitHubPopUp( userName ) 
  const [projectData, setProjectData] = useState([]);

  useEffect(() => 
    async function fetchData() 
      setProjectData(await GitHubFetch( userName ));
    
    fetchData();
  , []);
  
  useEffect(() => 
    console.log("the project data i fetched is: ", projectData);
  , [ projectData ]);

  return (
    <>
      <OverlayTrigger
        placement="right"
        delay= show: 250, hide: 5000 
        overlay=
          <Popover>
            <Popover.Title as="h3">`GitHub Projects`</Popover.Title>
            <Popover.Content>
              <strong>userName's GitHub Projects:</strong>
              projectData.length > 0 && (
                <GitHubListDisplay ...projectData />
              )
            </Popover.Content>
          </Popover>
        
      >
        <Button variant="link">userName</Button>
      </OverlayTrigger>
    </>
  );

【讨论】:

这适用于控制台。记录项目数据,但仍然无法将其传递给 组件.. 它始终未定义 这样传递projectData 【参考方案2】:

您不能按照自己的意愿将forEach 用于async await。只需使用现代的 for … of 循环,其中 await 将按您的预期工作。

参考here


但是,最佳做法是使用Promise.all

【讨论】:

不幸的是,使用 for ... of 方法以及作为 Promise.all 的替代方法的 Array.prototype.reduce 方法仍然未定义/相同的行为来自同一个线程。我想确保这也可以:( 你能用 for...of 更新你的问题吗?并附上 returnArray 值 已更新.. 我也尝试使用 promise.all 得到相同的结果。虽然我不确定我是否正确使用它 我发现问题,添加userName依赖到使用效果 useEffect(() => ... , [ userName ]);

以上是关于在反应中使用 async/await 未定义的主要内容,如果未能解决你的问题,请参考以下文章

async/await __generator 未定义

嵌套的 try、catch 和 async、await 请求

es6之 async await 使用小计

使用带有 webpack-simple 配置的 async/await 抛出错误:RegeneratorRuntime 未定义

理解ES7中的async/await

如何使用 react-hooks-testing-library 测试自定义 async/await 钩子