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?
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.
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.
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.
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.
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 ); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With