Skip to content

Instantly share code, notes, and snippets.

@janmarek
Last active December 27, 2022 21:23
Show Gist options
  • Save janmarek/cd8db68c82d57c2bc9c7 to your computer and use it in GitHub Desktop.
Save janmarek/cd8db68c82d57c2bc9c7 to your computer and use it in GitHub Desktop.
Save part of a Redux store to local storage
function mergeData(reducerDefaults, storedData) {
return {
...reducerDefaults,
...storedData,
};
}
function createLocalStorageReducer(
reducer,
key,
serialize = JSON.stringify,
deserialize = JSON.parse,
merge = mergeData,
storage = window.localStorage
) {
if (typeof storage !== 'object' || storage === null) {
return reducer;
}
return (state, action) => {
if (typeof state === 'undefined') {
const reducerDefaults = reducer(undefined, {});
// try load from local storage
const stored = storage.getItem(key);
const storedData = typeof stored === 'string' ? deserialize(stored) : {};
state = merge(reducerDefaults, storedData);
}
const newState = reducer(state, action);
if (state !== newState) {
storage.setItem(key, serialize(newState));
}
return newState;
};
}
export default createLocalStorageReducer;
import createLocalStorageReducer from '../createLocalStorageReducer';
describe('createLocalStorageReducer', function () {
const originalReducer = (state = {a: 1, b: 2}, action) => {
switch (action.type) {
case 'INC':
return {...state, a: state.a + 1};
case 'DEC':
return {...state, a: state.a - 1};
default:
return state;
}
};
it('populates default data', function () {
const storage = {
getItem: () => null,
};
const reducer = createLocalStorageReducer(originalReducer, 'key', undefined, undefined, undefined, storage);
expect(reducer(undefined, {})).to.eql({a: 1, b: 2});
});
it('populates default data from local storage', function () {
let calledKey;
const storage = {
getItem(key) {
calledKey = key;
return '{"a": 4}';
}
};
const reducer = createLocalStorageReducer(originalReducer, 'key', undefined, undefined, undefined, storage);
expect(reducer(undefined, {})).to.eql({a: 4, b: 2});
expect(calledKey).to.be('key');
});
it('saves new data and returns new state', function () {
let calledKey, calledData;
const storage = {
setItem(key, data) {
calledKey = key;
calledData = data;
},
};
const reducer = createLocalStorageReducer(originalReducer, 'key', undefined, undefined, undefined, storage);
expect(reducer({a: 4, b: 2}, {type: 'INC'})).to.eql({a: 5, b: 2});
expect(calledKey).to.be('key');
expect(calledData).to.be('{"a":5,"b":2}');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment