redux-async-initial-state
Version:
It is simple redux middleware that helps you load redux initial state asynchronously
127 lines (98 loc) • 3.51 kB
Markdown
Redux Async Initial State
=============
Redux [middleware](http://redux.js.org/docs/advanced/Middleware.html) for async loading of initial app state.
[](https://travis-ci.org/KELiON/redux-async-initial-state)
[](https://www.npmjs.com/package/redux-async-initial-state)
```bash
npm install --save redux-async-initial-state
```
## What? Why?
With [redux](http://redux.js.org) it is quite simple to synchronously load initial state, i.e. from localStorage:
```javascript
...
const initialState = JSON.parse(localStorage.getItem('state'));
const store = storeCreator(reducer, initialState);
```
But it becomes quite complicated to do it asynchronously, i.e. from server or from async storage, like in [React Native](https://facebook.github.io/react-native/docs/asyncstorage.html). This middleware do it for you.
## Usage
1. Add package
```bash
npm install --save redux-async-initial-state
```
2. Change your reducer and add middleware:
before:
```javascript
import { createStore, combineReducers } from 'redux'
import * as reducers from 'reducers'
const reducer = combineReducers(reducers)
const store = createStore(reducer)
```
After
```javascript
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import * as reducers from 'reducers';
import * as asyncInitialState from 'redux-async-initial-state';
// We need outerReducer to replace full state as soon as it loaded
const reducer = asyncInitialState.outerReducer(combineReducers({
...reducers,
// We need innerReducer to store loading state, i.e. for showing loading spinner
// If you don't need to handle loading state you may skip it
asyncInitialState: asyncInitialState.innerReducer,
}));
// Load state function
// Should return promise that resolves application state
const loadStore = () => {
return new Promise(resolve => {
fetch('/store')
.then(response => response.json())
.then(resolve);
});
}
const store = createStore(
reducer,
compose(applyMiddleware(asyncInitialState.middleware(loadStore)))
);
```
### Partial replace
In case when you're loading only part of your store initially, you can add `getCurrentState` argument in `loadStore` function. So, if you have some complex shape of your reducer and you need to replace only some of keys in your store (`currentUser` in example below):
```js
const loadStore = (getCurrentState) => {
return new Promise(resolve => {
fetch('/current_user.json')
.then(response => response.json())
.then(user => {
resolve({
// reuse state that was before loading current user
...getCurrentState(),
// and replace only `currentUser` key
currentUser: user
})
});
});
}
```
## Reducer
The shape of `innerReducer` is:
```javascript
{
loaded: false,
loading: false,
error: false
}
```
You can add it to you reducer if you want to handle loading state, i.e. to show loading spinner. Here is React example (it uses reducer, described above):
```javascript
import React from 'react';
import { connect } from 'react-redux';
(state => ({
loading: state.asyncInitialState.loading,
}))
class MyComponent extends React.Component {
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return ...;
}
}
```