【问题标题】:undefined using async/await in react在反应中使用 async/await 未定义
【发布时间】: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()。

标签: javascript reactjs asynchronous async-await


【解决方案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 ]);
猜你喜欢
  • 2021-10-05
  • 2020-06-06
  • 1970-01-01
  • 2017-06-09
  • 2017-07-13
  • 2018-05-24
  • 1970-01-01
  • 2021-10-21
  • 1970-01-01
相关资源
最近更新 更多