Reputation: 7707
I'd like to know in which different ways can we use async/await in a React Redux (with thunk) and if there are good conventions, what are they? I think it'll be nice to have:
then()
, as in this.props.myAction.then(...)Can we NOT have the async keyword in the class method, but in the method body instead? For example:
async doSomething () { const data = await this.props.myAction() console.log(data) }
// But maybe (it's failing for me, if the action is similar to my working action example *see below) doSomething () { const handler = async () => await this.props.myAction() // I guess the await here is redundant, but added to be clear to you const data = handler() console.log(data) }
My working solution at the moment follows:
// MOCK data
const MOCK_DATA = [1, 2, 3, 4, 5]
// Action
export function myAction (payload) {
return async (dispatch) => {
const getter = () => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({serverResponse: MOCK_DATA})
}, 1200)
})
return promise
}
try {
return await getter()
} catch (error) {
console.log(error)
}
}
}
// Container
class Foobar extends Component {
async doSomething () {
const data = await this.props.myAction()
}
render () {
return (
<div>
<button onClick={this.doSomething}>Do something!</button>
</div>
)
}
}
Upvotes: 0
Views: 1035
Reputation: 1036
The problem with "await" is you are Blocking the event loop and with Thunk you have to handle the Promises & dispatcher directly.
There is an alternative to Thunk that is more easy to use. redux-auto
from the documantasion
redux-auto fixed this asynchronous problem simply by allowing you to create an "action" function that returns a promise. To accompany your "default" function action logic.
The idea is to have each action in a specific file. co-locating the server call in the file with reducer functions for "pending", "fulfilled" and "rejected". This makes handling promises very easy.
You example would look like this:
// MOCK data
const MOCK_DATA = [1, 2, 3, 4, 5]
// data/serverThing.js
export default function (data, payload, stage, result) {
switch(stage){
case 'FULFILLED':
return result.serverResponse;
case 'REJECTED':
const error = result;
console.log(error)
case 'PENDING':
default :
break;
}
return data;
}
export function action (payload) {
return Promise.resolve({serverResponse: MOCK_DATA})
}
// Container
import React from "react"
import actions from 'redux-auto'
import { connect } from 'react-redux'
class Foobar extends Component {
const loading = (true === this.props.data.async.serverThing) ? "loading..." : "";
render () {
return (
<div>
<button onClick={()=>actions.data.serverThing()}>Do something!</button> { loading }
</div>
)
}
}
const mapStateToProps = ( { data }) => {
return { data }
};
export default connect( mapStateToProps )(Foobar);
It also automatically attaches a helper object(called "async") to the prototype of your state, allowing you to track in your UI, requested transitions.
Upvotes: 2