middleware to enable async data fetching as the result of a dispatched action
$ npm install @travi/redux-fetch-middleware --save
As a single middleware
import {createStore, applyMiddleware} from 'redux';
import fetchMiddlewareFactory from '@travi/redux-fetch-middleware';
import reducer from './reducer';
export default function ({session}) {
return createStore(reducer, applyMiddleware(fetchMiddlewareFactory(session)));
}
import {createStore, applyMiddleware, compose} from 'redux';
import fetchMiddlewareFactory from '@travi/redux-fetch-middleware';
import reducer from './reducer';
import DevTools from './DevTools'
export default function ({session}) {
return createStore(reducer, compose(applyMiddleware(fetchMiddlewareFactory(session)), DevTools.instrument()));
}
Be sure to export a createFetcher
named function that takes a session
object
export function createFetcher(session) {
const authToken = session.auth.token;
return {
async fetchFoo() {
return await getFoo(authToken);
},
async fetchBar() {
return await getBar(authToken);
}
};
}
Dispatch an action that does not define type
, but instead contains:
fetch
: a function that takes a reference to the client module to give access to the methods that do the actual data fetchinginitial
: the action type that should be dispatched when the data fetch is initiatedsuccess
: the action type that should be dispatched when the data has been successfully received. the received resource will be passed in theresource
attribute of this action.failure
: the action type that should be dispatched when the fetch result in an error. the resulting error will be passed as theerror
attribute of this action.data
: the data that you would like access to in your dispatched methods. the resulting data will be passed as base level attributes to theresource
.retry
(optional): a predicate function that enables instructing the middleware to retry (or poll) the fetch under certain conditions.- The predicate function is expected to be implemented in error-first style, meaning that the error will be provided as the first argument in the failure scenario, and the response will be provided as the second argument in the success scenario
- The predicate function should return a boolean to instruct the middleware whether to repeat the call again or not
- When the function is not provided, the default will be the same as if the
predicate returned
false
, so the fetch will not be repeated by default - When a retry is requested, the repeated request will be delayed by three seconds
export function loadFoo(id) {
return {
fetch: (client) => client.getFoo(id),
retry: (err, response) => {
if (err) return true;
return (response && 'in-progress' === response['completion-status']);
},
initiate: LOAD_FOO,
success: FOO_LOADED,
failure: FOO_LOAD_FAILED,
data: {id, foo:'bar'}
};
}
export default function reducer(state, action) {
switch (action.type) {
case LOAD_FOO:
return state.merge({loading: true, loaded: false, foo: {}});
case FOO_LOADED:
return state.merge({loading: false, loaded: true, foo: action.resource});
case FOO_LOAD_FAILED:
return state.merge({loading: false, error: action.error});
default:
return state;
}
}
Register your data-fetcher factory with @travi/ioc
This enables you to register different data-fetchers in different contexts, server vs browser
register('fetcher-factory', fetcherFactory);
$ nvm install
$ npm install
$ npm test