Last active
July 2, 2020 13:50
-
-
Save nihlton/b5a32b641eb84e115a7a137bc38780d9 to your computer and use it in GitHub Desktop.
Persist Redux in localStorage, with an expiration schedule for each store key.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getInitialState, syncLocalStorageWithRedux } from './util-localStorage' | |
const reduxStorageKey = 'my-application:' | |
const ONE_SECOND = 1000 | |
const ONE_MINUTE = ONE_SECOND * 60 | |
const ONE_HOUR = ONE_MINUTE * 60 | |
const ONE_DAY = ONE_HOUR * 24 | |
const ONE_YEAR = ONE_DAY * 365 | |
// create a white list. key is the redux store key, and lifeSpan is | |
// the length of time the value should be stored for in milliseconds. | |
const reduxStorageWhiteList = [ | |
{ key: 'user', lifeSpan: ONE_YEAR }, | |
{ key: 'siteConfig', lifeSpan: ONE_DAY }, | |
{ key: 'siteContent', lifeSpan: ONE_MINUTE * 5 } | |
] | |
const initialState = getInitialState(reduxStorageKey) | |
const store = createStore(initialState) | |
store.subscribe(() => syncLocalStorageWithRedux(reduxStorageKey, reduxStorageWhiteList, store.getState())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const getInitialState = (storageKey) => { | |
// iterate through local storage, and extract items whose key start with the storage key | |
// check if they've expired. if they haven't, add them to initial state. If they have, delete them. | |
// When we've iterated through all of them, return initial state. | |
let initialState = {} | |
Object.keys(window.localStorage).forEach(key => { | |
const isPersistedItem = key.indexOf(storageKey) === 0 | |
const localSnapShot = isPersistedItem && JSON.parse(window.localStorage.getItem(key)) | |
const isAlive = localSnapShot && localSnapShot.timeOfDeath > Date.now() | |
const isDead = localSnapShot && localSnapShot.timeOfDeath < Date.now() | |
if (isAlive) { | |
initialState[key.split(storageKey)[1]] = JSON.parse(localSnapShot.json) | |
} | |
if (isDead) { | |
window.localStorage.removeItem(key) | |
} | |
}) | |
return initialState | |
} | |
export const syncLocalStorageWithRedux = (storageKey, whiteList, state) => { | |
// iterate through our white list. | |
// if the value hasn't been saved before, or the value in redux has | |
// changed since the last time this was saved to local storage, | |
// extend the life span and save the new value. | |
whiteList.forEach(item => { | |
const thisItemKey = storageKey + item.key | |
const storeJSON = JSON.stringify(state[item.key]) | |
const storeSnapShot = JSON.stringify({ timeOfDeath: Date.now() + item.lifeSpan, json: storeJSON }) | |
const localSnapShot = window.localStorage.getItem(thisItemKey) | |
const localSnapShotValue = localSnapShot && JSON.parse(localSnapShot) | |
if (!localSnapShotValue || storeJSON !== localSnapShotValue.json) { | |
window.localStorage.setItem(thisItemKey, storeSnapShot) | |
} | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment