Skip to content

Instantly share code, notes, and snippets.

@trybick
Last active May 10, 2020 23:42
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 trybick/1145fb7d1b1da8270eba0a67943c08f8 to your computer and use it in GitHub Desktop.
Save trybick/1145fb7d1b1da8270eba0a67943c08f8 to your computer and use it in GitHub Desktop.
Redux stack using Typescript, Thunk, and Redux Persist
import axios from 'axios';
import { AppThunk } from 'store';
import { baseUrl } from 'utils/constants';
import handleErrors from 'utils/handleErrors';
export const FETCH_USER_FOLLOWS = 'FETCH_USER_FOLLOWS';
export const REMOVE_FROM_FOLLOWED_SHOWS = 'REMOVE_FROM_FOLLOWED_SHOWS';
export const SAVE_TO_FOLLOWED_SHOWS = 'SAVE_TO_FOLLOWED_SHOWS';
export const SET_HAS_LOCAL_WARNING_TOAST_BEEN_SHOWN = 'SET_HAS_LOCAL_WARNING_TOAST_BEEN_SHOWN';
export const SET_IS_LOGGED_IN_FALSE = 'SET_IS_LOGGED_IN_FALSE';
export const SET_IS_LOGGED_IN_TRUE = 'SET_IS_LOGGED_IN_TRUE';
export const UNREGISTERED_CLEAR_FOLLOWED_SHOWS = 'UNREGISTERED_CLEAR_FOLLOWED_SHOWS';
export const UNREGISTERED_REMOVE_FROM_FOLLOWED_SHOWS = 'UNREGISTERED_REMOVE_FROM_FOLLOWED_SHOWS';
export const UNREGISTERED_SAVE_TO_FOLLOWED_SHOWS = 'UNREGISTERED_SAVE_TO_FOLLOWED_SHOWS';
export const fetchfollowedShowsAction = (): AppThunk => (dispatch) =>
axios
.get(`${baseUrl}/follow`, {
params: { token: localStorage.getItem('jwt') },
})
.then(({ data }) => {
dispatch({
type: FETCH_USER_FOLLOWS,
payload: data,
});
})
.catch(handleErrors);
export const setHasLocalWarningToastBeenShownAction = (): AppThunk => (dispatch) => {
dispatch({
type: SET_HAS_LOCAL_WARNING_TOAST_BEEN_SHOWN,
});
};
export const setIsLoggedOutAction = (): AppThunk => (dispatch) => {
dispatch({
type: SET_IS_LOGGED_IN_FALSE,
});
};
export const setIsLoggedInAction = (): AppThunk => (dispatch) => {
dispatch({
type: SET_IS_LOGGED_IN_TRUE,
});
};
export const removeFromFollowedShowsAction = (showId: string): AppThunk => (dispatch) => {
dispatch({
type: REMOVE_FROM_FOLLOWED_SHOWS,
payload: showId,
});
};
export const saveToFollowedShowsAction = (showId: string): AppThunk => (dispatch) => {
dispatch({
type: SAVE_TO_FOLLOWED_SHOWS,
payload: showId,
});
};
export const unregisteredClearFollowedShowsAction = (): AppThunk => (dispatch) => {
dispatch({
type: UNREGISTERED_CLEAR_FOLLOWED_SHOWS,
});
};
export const unregisteredSaveToFollowedShowsAction = (showId: string): AppThunk => (dispatch) => {
dispatch({
type: UNREGISTERED_SAVE_TO_FOLLOWED_SHOWS,
payload: showId,
});
};
export const unregisteredRemoveFromFollowedShowsAction = (showId: string): AppThunk => (
dispatch
) => {
dispatch({
type: UNREGISTERED_REMOVE_FROM_FOLLOWED_SHOWS,
payload: showId,
});
};
import { Action, Reducer, AnyAction } from 'redux';
import { AppState } from 'store';
import {
FETCH_USER_FOLLOWS,
REMOVE_FROM_FOLLOWED_SHOWS,
SAVE_TO_FOLLOWED_SHOWS,
SET_IS_LOGGED_IN_FALSE,
SET_IS_LOGGED_IN_TRUE,
SET_HAS_LOCAL_WARNING_TOAST_BEEN_SHOWN,
UNREGISTERED_CLEAR_FOLLOWED_SHOWS,
UNREGISTERED_REMOVE_FROM_FOLLOWED_SHOWS,
UNREGISTERED_SAVE_TO_FOLLOWED_SHOWS,
} from './actions';
import { ID } from 'types/common';
export interface UserState {
followedShows: ID[];
hasLocalWarningToastBeenShown: boolean;
isLoggedIn: boolean;
unregisteredFollowedShows: ID[];
}
const initialState = {
followedShows: [],
hasLocalWarningToastBeenShown: false,
isLoggedIn: false,
unregisteredFollowedShows: [],
};
export const selectFollowedShows = (state: AppState) => state.user.followedShows;
export const selectHasLocalWarningToastBeenShown = (state: AppState) =>
state.user.hasLocalWarningToastBeenShown;
export const selectIsLoggedIn = (state: AppState) => state.user.isLoggedIn;
export const selectUnregisteredFollowedShows = (state: AppState) =>
state.user.unregisteredFollowedShows;
export const userReducer: Reducer<UserState, Action> = (
state = initialState,
action: AnyAction
) => {
switch (action.type) {
case FETCH_USER_FOLLOWS: {
return {
...state,
followedShows: action.payload,
};
}
case REMOVE_FROM_FOLLOWED_SHOWS: {
return {
...state,
followedShows: state.followedShows.filter((showId) => showId !== action.payload),
};
}
case SAVE_TO_FOLLOWED_SHOWS: {
return !state.followedShows.includes(action.payload)
? {
...state,
followedShows: [...state.followedShows, action.payload],
}
: state;
}
case SET_IS_LOGGED_IN_FALSE: {
return {
...state,
isLoggedIn: false,
followedShows: [],
};
}
case SET_IS_LOGGED_IN_TRUE: {
return {
...state,
isLoggedIn: true,
};
}
case SET_HAS_LOCAL_WARNING_TOAST_BEEN_SHOWN: {
return {
...state,
hasLocalWarningToastBeenShown: true,
};
}
case UNREGISTERED_CLEAR_FOLLOWED_SHOWS: {
return {
...state,
unregisteredFollowedShows: [],
};
}
case UNREGISTERED_REMOVE_FROM_FOLLOWED_SHOWS: {
return {
...state,
unregisteredFollowedShows: state.unregisteredFollowedShows.filter(
(showId) => showId !== action.payload
),
};
}
case UNREGISTERED_SAVE_TO_FOLLOWED_SHOWS: {
return !state.unregisteredFollowedShows.includes(action.payload)
? {
...state,
unregisteredFollowedShows: [...state.unregisteredFollowedShows, action.payload],
}
: state;
}
default:
return state;
}
};
import { Action, AnyAction, applyMiddleware, combineReducers, createStore, Store } from 'redux';
import thunk, { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { persistStore, persistReducer, Persistor } from 'redux-persist';
import { composeWithDevTools } from 'redux-devtools-extension';
import storage from 'redux-persist/lib/storage';
import { userReducer, UserState } from './user/reducers';
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
AppState,
unknown,
Action<string>
>;
export type AppThunkDispatch = ThunkDispatch<AppState, void, AnyAction>;
export type AppThunkPlainAction = () => void;
export type AppState = {
user: UserState;
};
const rootPersistConfig = {
key: 'root',
storage,
blacklist: ['user'],
};
const userPersistConfig = {
key: 'user',
storage: storage,
blacklist: ['hasLocalWarningToastBeenShown'],
};
const rootReducer = combineReducers({
user: persistReducer(userPersistConfig, userReducer),
});
const persistedReducer = persistReducer(rootPersistConfig, rootReducer);
const middlewares = [thunk];
const appliedMiddleware = applyMiddleware(...middlewares);
export default (): {
store: Store<{}, Action<any>> & {
dispatch: unknown;
};
persistor: Persistor;
} => {
const store = createStore(persistedReducer, composeWithDevTools(appliedMiddleware));
const persistor = persistStore(store);
return { store, persistor };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment