@larscom/ngrx-store-storagesync

Highly configurable state sync library between localStorage/sessionStorage
and @ngrx/store
(Angular)
Features
- ✓ Sync with
localStorage
and sessionStorage
- ✓ Storage option per feature state, for example:
- feature1 to
sessionStorage
- feature2 to
localStorage
- ✓ Exclude deeply nested properties
- ✓ Sync Reactive Forms (needs additional library)
Dependencies
@larscom/ngrx-store-storagesync
depends on @ngrx/store and Angular
Installation
npm install @larscom/ngrx-store-storagesync
Choose the version corresponding to your Angular version
>= 12 | >= 13.0.0 |
< 12 | <= 6.3.0 |
Usage
Include storageSyncReducer
in your meta-reducers array in StoreModule.forRoot
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { StoreModule } from '@ngrx/store'
import { routerReducer } from '@ngrx/router-store'
import { storageSync } from '@larscom/ngrx-store-storagesync'
import * as fromFeature1 from './feature/reducer'
export const reducers: ActionReducerMap<IRootState> = {
router: routerReducer,
feature1: fromFeature1.reducer
}
export function storageSyncReducer(reducer: ActionReducer<IRootState>): ActionReducer<IRootState> {
const metaReducer = storageSync<IRootState>({
features: [
{ stateKey: 'router', storageForFeature: window.sessionStorage },
{ stateKey: 'feature1', excludeKeys: ['auth.success', 'loading'] }
],
storage: window.localStorage
})
return metaReducer(reducer)
}
const metaReducers: MetaReducer<any>[] = [storageSyncReducer]
@NgModule({
imports: [BrowserModule, StoreModule.forRoot(reducers, { metaReducers })]
})
export class AppModule {}
Configuration
export interface IStorageSyncOptions<T> {
features: IFeatureOptions<T>[]
storage: Storage
version?: number
versionKey?: string
storageError?: (error: any) => void
rehydrate?: boolean
storageKeySerializer?: (key: string) => string
rehydrateStateMerger?: (state: T, rehydratedState: T) => T
}
export interface IFeatureOptions<T> {
stateKey: string
excludeKeys?: string[]
storageForFeature?: Storage
shouldSync?: (featureState: T[keyof T], state: T) => boolean
storageKeySerializerForFeature?: (key: string) => string
serialize?: (featureState: T[keyof T]) => string
deserialize?: (featureState: string) => T[keyof T]
}
Examples
Sync to different storage locations
You can sync to different storage locations per feature state.
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [
{ stateKey: 'feature1', storageForFeature: window.sessionStorage },
{ stateKey: 'feature2' }
],
storage: window.localStorage
})(reducer)
}
Exclude specific properties on state
Prevent specific properties from being synced to storage.
const state: IRootState = {
feature1: {
message: 'hello',
loading: false,
auth: {
loading: false,
loggedIn: false,
message: 'hello'
}
}
}
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [{ stateKey: 'feature1', excludeKeys: ['auth.loading', 'message'] }],
storage: window.localStorage
})(reducer)
}
Sync conditionally
Sync state to storage based on a condition.
const state: IRootState = {
checkMe: true,
feature1: {
rememberMe: false,
auth: {
loading: false,
message: 'hello'
}
}
}
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [
{
stateKey: 'feature1',
shouldSync: (feature1, state) => {
return feature1.rememberMe || state.checkMe
}
}
],
storage: window.localStorage
})(reducer)
}
Serialize state
Override the default serializer for the feature state.
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [
{
stateKey: 'feature1',
serialize: (feature1) => JSON.stringify(feature1)
}
],
storage: window.localStorage
})(reducer)
}
Deserialize state
Override the default deserializer for the feature state.
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [
{
stateKey: 'feature1',
deserialize: (feature1: string) => JSON.parse(feature1)
}
],
storage: window.localStorage
})(reducer)
}
Serialize storage key
Override the default storage key serializer.
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [{ stateKey: 'feature1' }],
storageKeySerializer: (key: string) => `abc_${key}`,
storage: window.localStorage
})(reducer)
}
Merge rehydrated state
Override the default rehydrated state merger.
export function storageSyncReducer(reducer: ActionReducer<IRootState>) {
return storageSync<IRootState>({
features: [{ stateKey: 'feature1' }],
rehydrateStateMerger: (state: IRootState, rehydratedState: IRootState) => {
return { ...state, ...rehydratedState }
},
storage: window.localStorage
})(reducer)
}