Really simple isomorphic fetch for Redux. Can be used in any Redux project that uses redux-api-middleware.
Recommended method for simple isomorphic HTTP data fetching in Roc.
npm install --save redux-fetcher
Import
import { createFetchAction, createFetchReducer } from 'redux-fetcher';
Create your fetch actions using createFetchAction
.
Create your fetch reducers using createFetchReducer
.
The example illustrates requesting some data from the open Github API.
const FETCH_REPOS = 'repos';
This can be any unique string that will identify your request and its corresponding key in the state tree.
const fetchRepos = createFetchAction(
FETCH_REPOS,
'https://api.github.com/users/rocjs/repos'
);
The action fetchRepos
can then be used with dispatch()
directly, or if using react-redux
through mapDispatchToProps
and used like normal in your React components.
The generated reducer will ensure that the state is updated according to the internal fetch actions.
const fetchReposReducer = createFetchReducer(FETCH_REPOS);
When adding your reducer to Redux using combineReducers
, it is important that the key is equivalent to the action/reducer identifier above:
const myReducers = combineReducers({
[FETCH_REPOS]: fetchReposReducer
});
Done!
For the rest of this section we assume
const state = store.getState();
After a successful dispatch of fetchRepos
and its following actions your data will be in state.repos.payload
along with state.repos.error
and state.repos.loading
. Some useful data like endpoint
is also set to state.repos.meta
. These can optionally be used to give a better user experience.
You can also pass in your own metadata.
When fetchAction
is dispatched the following will happen internally:
- It will check if the
fetch
should take place at all (See options) - It dispatches an action named
REPOS_FETCH_PENDING
- The
fetchReposReducer
handlesREPOS_FETCH_PENDING
and will set thestate.repos.loading
totrue
,state.repos.error
tofalse
andstate.repos.meta.endpoint
to the requested URL that is currently loading. - It (through
redux-api-middleware
) performs an isomorphicfetch
using theurl
. This operation is async, and what it does depends if the fetch fails or succeeds.
- It dispatches an action named
REPOS_FETCH_SUCCESS
. The response will be stored instate.repos.payload
.state.repos.error
andstate.repos.loading
will always be false after reducing a success. Againstate.repos.meta
will provideendpoint
, but also aresponse
object with some basic information.
- It dispatches an action named
REPOS_FETCH_FAILURE
.state.repos.payload
will contain the errorname
andmessage
.state.repos.error
will be set totrue
andstate.repos.loading
will be false after reducing an error.state.repos.meta
will provideendpoint
andresponse
.
Note: In case of a network-error, redux-api-middleware
will dispatch another PENDING
type action, but with error
set to true
. See agraboso/redux-api-middleware#26. This is likely to change in redux-api-middleware
3.x.x.
fetchAction(id, url, options, meta)
id
: string uniquely identifying your fetch operationurl
: string containing url to fetchoptions
: object
Default options:
{
force: false,
method: 'GET',
body: '',
headers: undefined,
credentials: undefined,
bailout: undefined
}
- `force`: boolean, set to true if you wish to perform fetch even if you have data in your store already. Only applies if you do not override bail yourself.
- `method`: string, HTTP method to use in fetch.
- `body`: string, request body to use (only applies to non-GET and non-HEAD requests)
- `headers`: object, specify custom HTTP headers to use in your request
- `credentials`: string, `omit`, `same-origin`, `include`. Include cookies in request?
- `bailout`: function. Is always executed before performing a request and will abort if it evaluates to true.
Your custom options passed will be shallow-merged with the default.
meta
: object or function(action, state, res) that returns object
The provided meta will be shallow-merged with the default metadata.
fetchReducer(id)
id
: string uniquely identifying your fetch operation
const cached = !!state[id].payload && !force;
return state[id].loading || cached;
It will bail if it is already fetching data
or if it already has data and is not forced
.
As mentioned in the API overview above we can enhance our resulting meta
with additional data.
createFetchAction(FETH_REPOS, 'https://api.github.com/users/rocjs/repos', {}, { importantData: 'xyz'} );
or
createFetchAction(FETH_REPOS, 'https://api.github.com/users/rocjs/repos', {}, () => { importantData: 'xyz'} );
This will result in the default metadata also containing importantData: 'xyz'