Skip to content

Instantly share code, notes, and snippets.

@nihlton
Last active July 2, 2020 13:50
Show Gist options
  • Save nihlton/b5a32b641eb84e115a7a137bc38780d9 to your computer and use it in GitHub Desktop.
Save nihlton/b5a32b641eb84e115a7a137bc38780d9 to your computer and use it in GitHub Desktop.
Persist Redux in localStorage, with an expiration schedule for each store key.
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()))
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