Last active
May 10, 2020 23:42
-
-
Save trybick/1145fb7d1b1da8270eba0a67943c08f8 to your computer and use it in GitHub Desktop.
Redux stack using Typescript, Thunk, and Redux Persist
This file contains 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 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, | |
}); | |
}; |
This file contains 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 { 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; | |
} | |
}; |
This file contains 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 { 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