Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async/await inside a React functional component

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

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

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:

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

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

const Dashboard = async props => {   const classes = useStyles();    const token = await fetchKey(props.auth); 

React complains mightily:

> 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.setState method to set some state, and then go on my merry way. However, I don't have that option in this functional component.

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

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.

like image 297
Yu Chen Avatar asked Sep 09 '19 03:09

Yu Chen


People also ask

How do you use async-await in functional component in React?

To use async and await inside a React functional component, we can define an async function inside the component and call it. We defined the getAnswer async function that calls axios to make a GET request to the API endpoint we want.

Can a React component be async?

There have been tweets lately stating that async/await does not work well with React components, unless there is a certain amount of complexity in how you deal with it. Async/await in components is a bugfest. Components have props/state that change over time.

How do I add async-await to function?

The async-await syntax helps with readability, allowing you to write the code as if it were using synchronous call patterns. To enable this method of communication, you'll need to modify your function prototype. In the declaration of the function prototype, before the word function, add the keyword async.


1 Answers

You will have to make sure two things

  • useEffect is similar to componentDidMount and componentDidUpdate, so if you use setState here then you need to restrict the code execution at some point when used as componentDidUpdate as shown below:
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   ); } 
like image 180
Milind Agrawal Avatar answered Sep 24 '22 02:09

Milind Agrawal