Give to redux some async useful utils to being more smart
Actually, if we have more async actions in our redux application, we can use these libs:
All of these contribute to transform the core flow of redux (that is sync) to an async workflow.
Developing redux application, it might be possible you have to download some data or doing some other async operations.
So, it is possible with the thunk middleware that help you to dispatch actions inside other actions.
But... Let me introduce some code for a download action.
// action type
const DOWNLOAD_TODOS_LOADING = 'DOWNLOAD_TODOS_LOADING';
const DOWNLOAD_TODOS_SUCCESS = 'DOWNLOAD_TODOS_SUCCESS';
const DOWNLOAD_TODOS_ERROR = 'DOWNLOAD_TODOS_ERROR';
// action
function downloadTodosActionCreator( ) {
return ( dispatch, getState ) => {
dispatch( { type: DOWNLOAD_TODOS_LOADING } );
// some fetch
fetchTodos( )
.then( ( result ) => {
dispatch( { type: DOWNLOAD_TODOS_SUCCESS, payload: result } );
} )
.catch( ( e ) => {
dispatch( { type: DOWNLOAD_TODOS_ERROR, error: e } );
} );
};
}In the previous example of code we have an async action that download todos using 3 actions:
We have too action type to do only one thing.
Also reducers has a lot of duplicated code, to manage the loading state in the store, errors or success with data, for each async action.
We could create some store enhancer and middleware to avoid rewriting all of these code lines.
So, redux-await seems to do something like this.
Using a middleware that run a Promise when you insert the AWAIT_MARKER into an action. You have also to insert the promise inside action's payload.
import { AWAIT_MARKER } from 'redux-await';
export const getTodos = () => ({
type: GET_TODOS,
AWAIT_MARKER,
payload: {
loadedTodos: api.getTodos(), // returns promise
},
});
export const addTodo = todo => ({
type: ADD_TODO,
AWAIT_MARKER,
payload: {
savedTodo: api.saveTodo(todo), // returns promise
},
});import { connect } from 'redux-await';
class Container extends Component {
render() {
const { todos, statuses, errors } = this.props;
// old code
//return <div>
// <MyList data={todos} />
//</div>;
// new code
return <div>
{ statuses.loadedTodos === 'pending' && <div>Loading...</div> }
{ statuses.loadedTodos === 'success' && <MyList data={loadedTodos} /> }
{ statuses.loadedTodos.status === 'failure' && <div>Oops: {errors.loadedTodos.message}</div> }
{ statuses.savedTodo === 'pending' && <div>Saving new savedTodo</div> }
{ statuses.savedTodo === 'failure' && <div>There was an error saving</div> }
</div>;
}
}
export default connect(state => state.todos)(Container)Now we have the ability to track all the async actions without writing all that boilerplate code.
Good idea!!
However, we have some trouble with this:
Text