javascript 在 React 功能组件中使用 async/await

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/57847626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:40:19  来源:igfitidea点击:

Using async/await inside a React functional component

javascriptreactjsasync-awaitmaterial-ui

提问by Yu Chen

I'm just beginning to use React for a project, and am really struggling with incorporating async/await functionality into one of my components.

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

I have an asynchronous function called fetchKeythat goes and gets an access key from an API I am serving via AWS API Gateway:

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

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;
  }
};

I am using React's Material UI theme, and waned to make use of one of its Dashboard templates. Unfortunately, the Dashboard template uses a functional stateless component:

我正在使用 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

The result of my console.log(token)is a Promise, which is expected, but the screenshot in my Google Chrome browser is somewhat contradictory - is it pending, or is it resolved? enter image description here

我的结果console.log(token)是 Promise,这是意料之中的,但是我在 Google Chrome 浏览器中的截图有些矛盾——是待定还是已解决? 在此处输入图片说明

Second, if I try instead token.then((data, error)=> console.log(data, error)), I get undefinedfor both variables. This seems to indicate to me that the function has not yet completed, and therefore has not resolved any values for dataor error. Yet, if I try to place a

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

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

  const token = await fetchKey(props.auth);

React complains mightily:

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)

Now, I'll be the first to state I don't have enough experience to understand what is going on with this error message. If this was a traditional React class component, I'd use the this.setStatemethod to set some state, and then go on my merry way. However, I don't have that option in this functional component.

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

How do I incorporate async/await logic into my functional React component?

如何将 async/await 逻辑合并到我的功能 React 组件中?

Edit:So I will just say I'm an idiot. The actual response object that is returned is not response.data.access_token. It was response.data.Item.access_token. Doh! That's why the result was being returned as undefined, even though the actual promise was resolved.

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

回答by Milind Agrawal

You will have to make sure two things

你必须确保两件事

  • useEffectis similar to componentDidMountand componentDidUpdate, so if you use setStatehere then you need to restrict at some point as shown below:
  • useEffect类似于componentDidMountand componentDidUpdate,所以如果你setState在这里使用,那么你需要在某个点进行限制,如下所示:
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
  );
}

回答by Tan Dat

With React Hooks, you can now achieve the same thing as Class component in functional component now.

使用 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

Also take a look at this: Using Async await in react component

也看看这个:Using Async await in react component

回答by Praneeth Paruchuri

const token = fetchKey(props.auth);

This returns a promise. To get the data from it, this is one way to do it:

这将返回一个承诺。要从中获取数据,这是一种方法:

let token = null;
fetchKey(props.auth).then(result => {
  console.log(result)
  token = result;
}).catch(e => {
  console.log(e)
})

Let me know if that works.

让我知道这是否有效。

I recreated a similar example: https://codesandbox.io/embed/quiet-wood-bbygk

我重新创建了一个类似的例子:https: //codesandbox.io/embed/quiet-wood-bbygk