在 React 函数组件中使用 async/await

我刚刚开始在一个项目中使用 React,并且正在努力将 async/await 功能合并到我的一个组件中。

我有一个名为异步函数的异步函数,它从我通过 AWS API Gateway 提供的 API 获取访问密钥:fetchKey

const fetchKey = async authProps => {
  try {
    const headers = {
      Authorization: authProps.idToken // using Cognito authorizer
    };

    const response = await axios.post(
      "https://MY_ENDPOINT.execute-api.us-east-1.amazonaws.com/v1/",
      API_GATEWAY_POST_PAYLOAD_TEMPLATE,
      {
        headers: headers
      }
    );
      return response.data.access_token;

  } catch (e) {
    console.log(`Axios request failed! : ${e}`);
    return e;
  }
};

我正在使用 React 的 Material UI 主题,并且逐渐停止使用其仪表板模板之一。遗憾的是,仪表板模板使用功能性无状态组件:

const Dashboard = props => {
  const classes = useStyles();

  const token = fetchKey(props.auth);
  console.log(token);

  return (
  ... rest of the functional component's code

我的结果是一个承诺,这是预期的,但我的谷歌浏览器浏览器中的屏幕截图有些矛盾 - 它是挂起的,还是解决了?console.log(token)enter image description here

其次,如果我尝试,我会得到两个变量。在我看来,这似乎表明该函数尚未完成,因此尚未解析 或 的任何值。然而,如果我试图放置一个token.then((data, error)=> console.log(data, error))undefineddataerror

const Dashboard = async props => {
  const classes = useStyles();

  const token = await fetchKey(props.auth);

React 强烈地抱怨:

> react-dom.development.js:57 Uncaught Invariant Violation: Objects are
> not valid as a React child (found: [object Promise]). If you meant to
> render a collection of children, use an array instead.
>     in Dashboard (at App.js:89)
>     in Route (at App.js:86)
>     in Switch (at App.js:80)
>     in div (at App.js:78)
>     in Router (created by BrowserRouter)
>     in BrowserRouter (at App.js:77)
>     in div (at App.js:76)
>     in ThemeProvider (at App.js:75)

现在,我将是第一个声明我没有足够的经验来理解此错误消息发生了什么的人。如果这是一个传统的 React 类组件,我会使用该方法来设置一些状态,然后继续我的快乐之路。但是,我在此功能组件中没有该选项。this.setState

如何将 async/await 逻辑合并到我的函数式 React 组件中?

编辑:所以我只会说我是个白痴。返回的实际响应对象不是 。它是.哎呀!这就是为什么结果被返回为未定义的原因,即使实际的承诺已解决。response.data.access_tokenresponse.data.Item.access_token


答案 1

你将不得不确保两件事

  • useEffect与 和 类似,因此,如果您在此处使用,则需要在使用时限制代码的执行,如下所示:componentDidMountcomponentDidUpdatesetStatecomponentDidUpdate
function Dashboard() {
  const [token, setToken] = useState('');

  useEffect(() => {
    // You need to restrict it at some point
    // This is just dummy code and should be replaced by actual
    if (!token) {
        getToken();
    }
  }, []);

  const getToken = async () => {
    const headers = {
      Authorization: authProps.idToken // using Cognito authorizer
    };
    const response = await axios.post(
      "https://MY_ENDPOINT.execute-api.us-east-1.amazonaws.com/v1/",
      API_GATEWAY_POST_PAYLOAD_TEMPLATE,
      { headers }
    );
    const data = await response.json();
    setToken(data.access_token);
  };

  return (
    ... rest of the functional component's code
  );
}

答案 2

使用 React Hooks,您现在可以在功能组件中实现与 Class 组件相同的功能组件。

import { useState, useEffect } from 'react';

const Dashboard = props => {
  const classes = useStyles();
  const [token, setToken] = useState(null);
  useEffect(() => {
     async function getToken() {
         const token = await fetchKey(props.auth);
         setToken(token);
     }
     getToken();
  }, [])


  return (
  ... rest of the functional component's code
  // Remember to handle the first render when token is null

另请看一下:在 react 组件中使用 Async await