Skip to content

Instantly share code, notes, and snippets.

@jfbloom22
Last active January 18, 2021 11:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jfbloom22/6ef92d9ff28007be8ce1154d28e7c66e to your computer and use it in GitHub Desktop.
Save jfbloom22/6ef92d9ff28007be8ce1154d28e7c66e to your computer and use it in GitHub Desktop.
redux configure store with redux-thunk, redux-offline, redux-persist v5, localForage, redux-devtools-extension, redux-immutable-state-invariant, axios, and typescript
import {
applyMiddleware,
createStore,
Middleware,
Store,
AnyAction,
compose
} from 'redux';
import { createOffline } from '@redux-offline/redux-offline';
// use redux-persist v5 because it has built in support for migrations
import { persistStore, persistReducer } from 'redux-persist';
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 '../constants/models';
import constants from '../constants/constants';
import rootReducer from '../reducers';
const effect = (
{
axiosRequest,
message
}: { axiosRequest: AxiosRequestConfig; message: string },
action: any
) =>
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: any, 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; // if it is a 400 error then discard
};
const persistConfig = {
key: 'state-core-care-app_',
debounce: 500,
storage: localForage
};
const {
middleware: offlineMiddleware,
enhanceReducer: offlineEnhanceReducer,
enhanceStore: offlineEnhanceStore
} = createOffline({
...offlineConfig,
persist: false,
effect,
discard
});
const persistedReducer = persistReducer(
persistConfig,
offlineEnhanceReducer(rootReducer)
);
export default function configureStore() {
if (process.env.NODE_ENV !== 'production') {
const store = createStore(
persistedReducer,
require('redux-devtools-extension').composeWithDevTools(
offlineEnhanceStore,
applyMiddleware(
thunk as ThunkMiddleware<IinitialState, any>,
require('redux-immutable-state-invariant').default(),
offlineMiddleware as Middleware<any, any, any>
)
)
) as Store<any, AnyAction>;
const persistor = persistStore(store);
return { persistor, store };
}
else {
const store = createStore(
persistedReducer,
compose(
applyMiddleware(thunk as ThunkMiddleware<IinitialState, any>),
offlineMiddleware as Middleware<any, any, any>
)
) as Store<any, AnyAction>;
const persistor = persistStore(store);
return { persistor, store };
}
}
@jfbloom22
Copy link
Author

jfbloom22 commented Oct 18, 2018

switched to localForage and upgraded to redux-persist v5 because it supports redux migrations. The above configuration also expects you to change the main App render statement to use PersistGate like so:

import { PersistGate } from 'redux-persist/integration/react'

// ... normal setup, create store and persistor, import components etc.

const { store, persistor } = configureStore();

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};

see redux-persist docs for more info: https://github.com/rt2zz/redux-persist#basic-usage

@jfbloom22
Copy link
Author

Created a more advanced config which adds a helper for persisting date objects, config for the persist reducer, and sections to help improve redux-devtools performance. https://gist.github.com/jfbloom22/093a75419db378cf42862ee11375903b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment