Skip to content

Instantly share code, notes, and snippets.

@awendland
Forked from heyimalex/WebStorage.js
Last active December 14, 2015 02:31
Show Gist options
  • Save awendland/baa6fefb552356865a65 to your computer and use it in GitHub Desktop.
Save awendland/baa6fefb552356865a65 to your computer and use it in GitHub Desktop.
localStorage sync with redux and TypeScript
import { reduxStorageReducer, ReduxStorage } from 'reduxStorage';
import myReducer from './myReducer';
function compose(...reducers) {
return (state, action) => {
return reducers.reduce((reducedState, reducer) => {
return reducer(reducedState, action);
}, state);
};
}
const finalReducer = compose(myReducer, reduxStorageReducer);
const storage = new ReduxStorage('redux');
const redux = createRedux(finalReducer, storage.load());
storage.connect(redux);
import WebStorage from 'WebStorage';
const STORAGE_SYNC = 'STORAGE_SYNC';
export const actions = { STORAGE_SYNC };
export function syncActionCreator(state) {
return {
type: STORAGE_SYNC,
synced: state,
};
}
export function reduxStorageReducer(state, action) {
if (action.type === STORAGE_SYNC) {
// Depends on state being an object|null|undefined
return Object.assign({}, state, action.synced);
} else {
return state;
}
}
export class ReduxStorage extends WebStorage {
connect(redux, actionCreator = syncActionCreator, listen = true) {
redux.subscribe(() => this.save(redux.getState()));
if (listen) {
this.listen(() => redux.dispatch(actionCreator(this.load())));
}
}
}
export default class WebStorage {
private key: string;
private storageArea: Storage;
constructor(key: string, storageArea = window.localStorage) {
this.key = key;
this.storageArea = storageArea;
}
load<T>(defaultValue?: T): T {
const serialized = this.storageArea.getItem(this.key);
return serialized === null ? defaultValue : this.deserialize(serialized);
}
/**
* Save a JSON serializable object into the data store
*
* @param {any} data [description]
*/
save(data: any): void {
if (data === undefined) {
this.storageArea.removeItem(this.key);
} else {
this.storageArea.setItem(this.key, this.serialize(data));
}
}
/**
* Clear this storage section from the storage area
*/
clear(): void {
this.storageArea.removeItem(this.key);
}
private serialize(value) {
return JSON.stringify(value);
}
private deserialize(value) {
return JSON.parse(value);
}
/**
* Listen for changes in the storage area that occur from other pages
* on the domain
*
* @param {Function} callback Single parameter is a StorageEvent
* @return {Function} Function to remove the listener
*/
listen(callback: (StorageEvent) => void): () => void {
const handler = (e) => {
if (e.key === this.key && e.storageArea === this.storageArea) {
callback(e);
}
};
window.addEventListener('storage', handler);
return () => window.removeEventListener('storage', handler);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment