import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
function definePromiseMiddlewareHooks() {
return {
response: (data, next) => next(data);
request: (data, next) => {
data.type = `${data.type}Request`;
next(data);
},
error: (data, next) => {
let { error } = data;
let err = error.data && error.data.error || error;
data.error = err;
data.type = `${data.type}Error`;
next(data);
}
}
}
export default applyMiddleware(
promiseMiddleware.bind(null, definePromiseMiddlewareHooks());
)(createStore);
There you have two options to use promise in your actions. First is common way define a promise
property.
const foo = () => ({
type: 'FOO',
promise: new Promise();
});
Or monkey patching the promise object.
const foo = () => {
return Object.assign(new Promise(), type: 'FOO');
};
The second wariant is very useful when you work a lot with certain API methods, often returning promises at the moment.
npm install redux-promise-middleware -s
❁ Handle promise process:
The library provide possibility to handle request
, response
, error
globally via overriding the default params in the redux-pirate-promise
. By the default it doenst modify the flow. You can work with promises like with pure function without any overhead.
let {
request = (data, next) => {},
response = (data, next) => next(data),
error = (data, next) => next(data)
} = params;
By we found often it's good to trigger store on the request. For examples to show the progress to end user.
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
let params = {
response: (data, next) => {
data.type = 'LOADING';
next(data);
}
};
export default applyMiddleware(
promiseMiddleware.bind(null, params);
)(createStore);
ϟ Global error handling: The often case, the promise return the error. You needs to handle it some how.
//store.js
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
let params = {
response: (data, next) => {
data.type = `${data.type}Error`;
next(data);
}
};
export default applyMiddleware(
promiseMiddleware.bind(null, params);
)(createStore);
//reducers.js
export function errors(state = [], action) {
if (action.type.endsWith('Error')) {
return [...state, action.error];
}
if (action.type === types.clearErrors) {
return [];
}
return state;
}
It allow you format error message one place and show errors popup simpler way.
❤ Action chaining: As for me the redux-thunk is overcomplicated to use. Let's tho a bit we already have promises in many places: API, Async / Await methods, external libraries why do we drop native promise changing wrapping promises to object?
Like redux-promise-middleware do
// implicit promise
const foo = () => ({
type: 'FOO',
payload: new Promise()
});
// explicit promise
const foo = () => ({
type: 'FOO',
payload: {
promise: new Promise()
}
});
When we extends promise object with redux
type constant. We can have native support of chaning, and no need to bring complex solutions like redux-thunk
.
const foo = () => {
return Object.assign(new Promise(), type: 'FOO');
};
const bar = () => {
return Object.assign(new Promise(), type: 'BAR');
};
So later in the application we can do like that:
foo()
.then(bar)
.then(()=> {
let state = store.getState();
});
or using async await
await foo();
await bar();
let state = store.getState();
This module was developed to act with redux-pirate-actions together.
- the minimal store should looks like: how to create store
- the minimal controller should looks like: how to use
Copyright (c) 2017 pirateminds.com. Licensed with The MIT License (MIT)