Skip to content

Instantly share code, notes, and snippets.

@jfbloom22
Last active June 20, 2019 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jfbloom22/093a75419db378cf42862ee11375903b to your computer and use it in GitHub Desktop.
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
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