Leverage localStorage to cache REDUX store data for slow API calls
const LIST_REQUEST_SENT = 'LIST_REQUEST_SENT'
const LIST_REQUEST_SUCCESS = 'LIST_REQUEST_SUCCESS'
const UPDATE_LIST = 'UPDATE_LIST'
const LIST_ADD_ITEM = 'LIST_ADD_ITEM'
const LOCAL_STORAGE_EXPIRATION_PERIOD = 604800000 // 7 days
const listRequestSent = () => ({
type: LIST_REQUEST_SENT,
})
const listRequestSuccess = () => ({
type: LIST_REQUEST_SUCCESS,
})
const updateList = list => ({
type: UPDATE_LIST,
list,
})
const listAddItem = (item) => ({
type: LIST_ADD_ITEM,
item,
})
/**
* Handle fetching and storing of list items
*
*/
export const handleGetList = () => (
(dispatch, getState) => {
const { items } = getState().list
// only if list is empty do we want to set the loading state
if (items.length === 0) {
dispatch(listRequestSent())
}
// api call to fetch list items
apiGetList()
.then((res) => {
const items = res.data.result
// update the localStorage list items
setListLocalStorage(items)
// update the list items in the store
dispatch(updateList(items))
dispatch(listRequestSuccess())
})
}
)
/**
* Create new biller
*
* @param {object} item
*/
export const handleAddItem = (item) => (
(dispatch, getState) => {
dispatch(listRequestSent())
apiCreateListItem()
.then((res) => {
const item = res.data.result
// update the localStorage billers list
const { items } = getState().list
const itemsClone = items.slice()
itemsClone.push(item)
setListLocalStorage(itemsClone)
// update the store
dispatch(listAddItem(item))
dispatch(ListRequestSuccess())
})
}
)
/**
* Add the list to localStorage
*
* @param {array} items
*/
const setListLocalStorage = (items) => {
const now = new Date().getTime()
const listObject = { items }
// set the expiration time for the localStorage item
listObject.expiration = now + LOCAL_STORAGE_EXPIRATION_PERIOD
// store the object in localStorage
localStorage.setItem('list', JSON.stringify(list))
}
/**
* Fetch the billers array from localStorage
*/
const getListLocalStorage = () => {
// fetch the item from localStorage
const listObject = JSON.parse(localStorage.getItem('list'))
// get the current time
const now = new Date().getTime()
// check if localStorage item exists and it has not expired
if (listObject && listObject.expiration > now) {
return listObject.items
}
return []
}
/**
* Set the initial state
*/
const initialState = {
isRequesting: false,
list: getListLocalStorage(),
}
export default function list(state = initialState, action) {
switch (action.type) {
case LIST_REQUEST_SENT:
return {
...state,
isRequesting: true,
}
case LIST_REQUEST_SUCCESS:
return {
...state,
isRequesting: false,
}
case UPDATE_LIST:
return {
...state,
items: action.list,
}
case LIST_ADD_ITEM:
const items = state.items.slice()
items.push(action.item)
return {
...state,
items,
}
default: {
return state
}
}
}
const LIST_REQUEST_SENT = 'LIST_REQUEST_SENT'
const LIST_REQUEST_SUCCESS = 'LIST_REQUEST_SUCCESS'
const UPDATE_LIST = 'UPDATE_LIST'
const LIST_ADD_ITEM = 'LIST_ADD_ITEM'
const listRequestSent = () => ({
type: LIST_REQUEST_SENT,
})
const listRequestSuccess = () => ({
type: LIST_REQUEST_SUCCESS,
})
const updateList = list => ({
type: UPDATE_LIST,
list,
})
const listAddItem = (item) => ({
type: LIST_ADD_ITEM,
item,
})
/**
* Handle fetching and storing of list items
*
*/
export const handleGetList = () => (
(dispatch, getState) => {
dispatch(listRequestSent())
// api call to fetch list items
apiGetList()
.then((res) => {
const items = res.data.result
// update the list items in the store
dispatch(updateList(items))
dispatch(listRequestSuccess())
})
}
)
/**
* Create new biller
*
* @param {object} item
*/
export const handleAddItem = (item) => (
(dispatch, getState) => {
dispatch(listRequestSent())
apiAddListItem()
.then((res) => {
const item = res.data.result
// update the store
dispatch(listAddItem(item))
dispatch(ListRequestSuccess())
})
}
)
/**
* Set the initial state
*/
const initialState = {
isRequesting: false,
list: [],
}
export default function list(state = initialState, action) {
switch (action.type) {
case LIST_REQUEST_SENT:
return {
...state,
isRequesting: true,
}
case LIST_REQUEST_SUCCESS:
return {
...state,
isRequesting: false,
}
case UPDATE_LIST:
return {
...state,
items: action.list,
}
case LIST_ADD_ITEM:
const items = state.items.slice()
items.push(action.item)
return {
...state,
items,
}
default: {
return state
}
}
}