redux-persistence
v1.2.0
Published
Persistence layer for redux with flexible backends.
Downloads
787
Maintainers
Readme
Features
- Flexible storage engines
- indexedDb: based on window.indexedDb
- localStorage: based on window.localStorage
- Or for environments without
Promise
support localStorageFakePromise
- Or for environments without
- reactNativeAsyncStorage: based on
react-native/AsyncStorage
- remoteEndpoint: save/load via XHR
- Flexible state merger functions
- simple: merge plain old JS structures (default)
- immutablejs: merge plain old JS and Immutable objects
- Storage engines can be async
- Load and save actions that can be observed
{ type: 'REDUX_PERSISTENCE_SAVE', payload: /* state tree */ }
{ type: 'REDUX_PERSISTENCE_LOAD', payload: /* state tree */ }
- Various engine decorators
- Black- and whitelist actions from issuing a save operation
- Proper storage limit handling
- Typescript support out of the box
Usage
import * as storage from 'redux-persistence'
// Import redux and all your reducers as usual
import { createStore, applyMiddleware, combineReducers } from 'redux'
import * as reducers from './reducers'
// We need to wrap the base reducer, as this is the place where the loaded
// state will be injected.
//
// Note: The reducer does nothing special! It just listens for the LOAD
// action and merge in the provided state :)
// Note: A custom merger function can be passed as second argument
const reducer = storage.reducer(combineReducers(reducers))
// Now it's time to decide which storage engine should be used
//
// Note: The arguments to `createEngine` are different for every engine!
import createEngine from 'redux-storage-engine-localstorage'
const engine = createEngine('my-save-key')
// And with the engine we can create our middleware function. The middleware
// is responsible for calling `engine.save` with the current state afer
// every dispatched action.
//
// Note: you can declare an action filtering function in the options
const middleware = storage.createMiddleware(engine)
// As everything is prepared, we can go ahead and combine all parts as usual
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore)
const store = createStoreWithMiddleware(reducer)
// At this stage the whole system is in place and every action will trigger
// a save operation.
//
// BUT (!) an existing old state HAS NOT been restored yet! It's up to you to
// decide when this should happen. Most of the times you can/should do this
// right after the store object has been created.
// To load the previous state we create a loader function with our prepared
// engine. The result is a function that can be used on any store object you
// have at hand :)
const load = storage.createLoader(engine)
load(store)
// Notice that our load function will return a promise that can also be used
// to respond to the restore event.
load(store)
.then(newState => console.log('Loaded state:', newState))
.catch(() => console.log('Failed to load previous state'))
Details
This is a fork of redux-storage
The original library has issues as old as 2017. This library is meant to fix some of those while also providing out-of-the-box typescript support.
Engines, Decorators & Mergers
They all are published as own packages on npm. But as a convention all engines share the keyword redux-storage-engine, decorators can be found with redux-storage-decorator and mergers with redux-storage-merger. So it's pretty trivial to find all the additions to redux-storage you need :smile:
Actions
redux-storage will trigger actions after every load or save operation from the underlying engine.
You can use this, for example, to display a loading screen until the old state has been restored like this:
import { LOAD, SAVE } from 'redux-persistence'
function storeageAwareReducer(state = { loaded: false }, action) {
switch (action.type) {
case LOAD:
return { ...state, loaded: true }
case SAVE:
console.log('Something has changed and written to disk!')
default:
return state
}
}
Middleware
You can configure the middleware by passing a second argument to createMiddleware
.
filterAction
Return true
for any action that should be accepted by the middleware.
Example:
const blacklist = ['SOME_ACTION', 'SOME_OTHER_ACTION']
createMiddleware(engine, {
filterAction: action => !blacklist.includes(action.type)
})
transform
Transform and return a new state before saving to the psrovided storage engine.
Example:
createMiddleware(engine, {
transform: state => {
let newState = { ...state }
// Remove some items from the state before saving
for (let key in newState) {
if (newState[key].isFlagged) {
delete newState[key]
}
}
return newState
}
})
disableDispatchSaveAction
Don't dispatch a REDUX_PERSISTENCE_SAVE
action after saving to the provided storage engine, false
by default.
Example:
createMiddleware(engine, {
disableDispatchSaveAction: true
})
onError
Handle any errors thrown while trying to save to the provided storage engine.
Example:
createMiddleware(engine, {
onError: err => {
if (err instanceof DOMException && err.name === 'QuotaExceededError') {
// handle out of storage!
}
}
})