Last active
June 20, 2019 20:10
-
-
Save jfbloom22/093a75419db378cf42862ee11375903b to your computer and use it in GitHub Desktop.
Advanced redux configure store with redux-thunk, redux-offline, redux-persist v5, localForage, redux-devtools-extension, redux-immutable-state-invariant, axios, typescript, Trackjs, helper to persist date objects, redux-persist migrations
This file contains hidden or 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 { | |
applyMiddleware, | |
createStore, | |
Middleware, | |
Store, | |
AnyAction, | |
compose, | |
Reducer, | |
StoreEnhancer | |
} from 'redux'; | |
import { | |
createMigrate, | |
persistReducer, | |
persistStore, | |
TransformIn, | |
createTransform | |
} from 'redux-persist'; | |
import { createOffline } from '@redux-offline/redux-offline'; | |
import axios, { AxiosRequestConfig, AxiosError } from 'axios'; | |
import * as localForage from 'localforage'; | |
import offlineConfig from '@redux-offline/redux-offline/lib/defaults/index'; | |
import thunk, { ThunkMiddleware } from 'redux-thunk'; | |
import { IinitialState } from '../models'; | |
import { migrations } from './migrations'; | |
import { constants } from 'src/constants/constants'; | |
import rootReducer from '../reducers'; | |
import hardSet from 'redux-persist/lib/stateReconciler/hardSet'; | |
import TrackJSLogger from './TrackJSLogger'; | |
import initialState from 'src/reducers/initialState'; | |
/* | |
* handle persisisting date objects | |
*/ | |
const replacer = (key: string, value: any) => | |
value instanceof Date ? value.toISOString() : value; | |
const reviver = (key: string, value: any) => | |
typeof value === 'string' && | |
value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/) | |
? new Date(value) | |
: value; | |
export const encode = (toDeshydrate: TransformIn<IinitialState, string>) => | |
JSON.stringify(toDeshydrate, replacer); | |
export const decode = (toRehydrate: string) => JSON.parse(toRehydrate, reviver); | |
const effect = ( | |
{ | |
axiosRequest, | |
message | |
}: { axiosRequest: AxiosRequestConfig; message: string }, | |
action: AnyAction | |
) => | |
axios(axiosRequest).catch(err => { | |
console.error(message, err); | |
constants.handleError(err, message); | |
throw err; | |
}); | |
// if discard returns true, then it will try again | |
const discard = (error: AxiosError, action: AnyAction, retries: number) => { | |
const { request, response } = error; | |
if (!request) { | |
throw error; | |
} // There was an error creating the request | |
if (!response) { | |
return false; | |
} // There was no response | |
return 400 <= response.status && response.status < 500; | |
}; | |
const persistConfig = { | |
key: 'state-core-care-web', | |
debounce: 500, | |
storage: localForage, | |
version: parseInt( | |
(process.env.REACT_APP_VERSION || '0.0.0').replace(/\./g, ''), | |
10 | |
), | |
migrate: createMigrate(migrations, { debug: true }), | |
blacklist: [], | |
stateReconciler: hardSet, | |
transforms: [createTransform(encode, decode)] | |
}; | |
const offlineEnhancer = createOffline({ | |
...offlineConfig, | |
persist: false, | |
effect, | |
discard | |
}); | |
const persistedReducer: Reducer<IinitialState> = persistReducer( | |
persistConfig, | |
offlineEnhancer.enhanceReducer(rootReducer) | |
); | |
export default function configureStore() { | |
if (process.env.NODE_ENV !== 'production') { | |
const composeEnhancers = require('redux-devtools-extension').composeWithDevTools( | |
{ | |
actionsBlacklist: [ | |
'persist/REHYDRATE', | |
'persist/PERSIST', | |
], // this improves the perfomance of redux devtools | |
autoPause: true, | |
latency: 1000, | |
maxAge: 20, | |
shouldHotReload: false, | |
stateSanitizer: (state: IinitialState) => | |
state.example | |
? { ...state, example: '<<LONG_BLOB>>' } | |
: state | |
} | |
); | |
const store: Store<IinitialState, AnyAction> = createStore( | |
persistedReducer, | |
initialState, | |
composeEnhancers( | |
offlineEnhancer.enhanceStore, | |
applyMiddleware( | |
thunk as ThunkMiddleware<IinitialState, AnyAction>, | |
require('redux-immutable-state-invariant').default(), | |
offlineEnhancer.middleware as Middleware<any, IinitialState, any> | |
) | |
) | |
); | |
const persistor = persistStore(store); | |
return { persistor, store }; | |
} else { | |
const store: Store<IinitialState, AnyAction> = createStore( | |
persistedReducer, | |
initialState as IinitialState, | |
compose( | |
offlineEnhancer.enhanceStore as StoreEnhancer, | |
applyMiddleware( | |
thunk as ThunkMiddleware<IinitialState, AnyAction>, | |
offlineEnhancer.middleware as Middleware<any, IinitialState, any>, | |
TrackJSLogger | |
) | |
) | |
); | |
const persistor = persistStore(store); | |
return { persistor, store }; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment