Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
You can save a heck of a lot of boilerplate by switching to Redux Toolkit
import Api from "../../ajax/api";
import {createSlice} from '@reduxjs/toolkit';
import get from 'lodash/get';
export interface IPhotosState {
query: string;
totalHits: number;
hits: any[];
total: number;
}
const initializeState = (): IPhotosState => ({
query: "",
totalHits: 0,
hits: [],
total: 0
});
const api = new Api();
const photosSlice = createSlice({
name: 'photos',
initialState: {
photos: initializeState(),
photoCache: {},
isLoading: false,
},
reducers: {
loadPhotos(state, action){
state.photos = action.payload;
state.photoCache[action.payload.query] = action.payload;
state.isLoading = false;
},
setLoading(state, action){
state.isLoading = action.payload;
}
}
})
export const {actions, reducer} = photosSlice;
export const getPhotos = (query: string) => async (dispatch: any, getState: any) => {
const formattedQuery: string = query.trim().replace(/\s+/g, "+");
const state = getState();
const photoCache = state.photos.photoCache
const now = Date.now();
if (
photoCache[formattedQuery] &&
(now - photoCache[formattedQuery].cachedAt) / 36e5 < 24
) {
if (get(process, "env.NODE_ENV", "development") === "development") {
console.info(`Cache Hit for ${formattedQuery}`);
}
return dispatch(actions.loadPhotos(photoCache[formattedQuery]));
}
console.info(`No cache hit, grabing from server`);
try {
dispatch(actions.setLoading(true))
const response = await api.getImages(formattedQuery);
const {body} = response;
dispatch(actions.loadPhotos({cachedAt: now, query: formattedQuery, ...body}))
} catch (err){
dispatch(actions.setLoading(false))
console.error(err);
}
}
export default reducer;
// -- Reducer file -- //
import { IReduxAction } from "../actions/types";
import actionTypes from "../reduxTypes";
export interface IPhotosState {
query: string;
totalHits: number;
hits: any[];
total: number;
}
const initializeState = (): IPhotosState => ({
query: "",
totalHits: 0,
hits: [],
total: 0
});
export const photos = (
state: IPhotosState = initializeState(),
action: IReduxAction = { type: "" }
): any => {
switch (action.type) {
case actionTypes.photos.LOAD_PHOTOS:
return action.payload;
default:
return state;
}
};
export const photoCache = (
state: { [key: string]: IPhotosState } = {},
action: IReduxAction = { type: "" }
) => {
switch (action.type) {
case actionTypes.photos.LOAD_PHOTOS:
return { ...state, [action.payload.query]: action.payload };
default:
return state;
}
};
export const loading = (state = false, action: IReduxAction = { type: "" }) => {
switch (action.type) {
case actionTypes.photos.LOADING:
return action.payload;
case actionTypes.photos.LOAD_PHOTOS:
return false;
default:
return state;
}
};
// -- Actions file --//
import { IReduxAction, ISearchResult } from "./types";
import actionTypes from "../reduxTypes";
import Api from "../../ajax/api";
import { Dispatch } from "redux";
import * as get from "lodash.get";
// might want to use dependency injection instead of
// creating the instance of the Api class here for testing
const api = new Api();
export const setLoading = (payload: boolean): IReduxAction => ({
type: actionTypes.photos.LOADING,
payload
});
export const loadPhotos = (payload: any): IReduxAction => ({
type: actionTypes.photos.LOAD_PHOTOS,
payload
});
/* This function might do too much. Refactor? */
export const getPhotos = (query: string) => (
dispatch: Dispatch,
getState: any
) => {
const formattedQuery: string = query.trim().replace(/\s+/g, "+");
const { photoCache } = getState();
const now: number = Date.now();
if (
photoCache[formattedQuery] &&
(now - photoCache[formattedQuery].cachedAt) / 36e5 < 24
) {
if (get(process, "env.NODE_ENV", "development") === "development") {
console.info(`Cache Hit for ${formattedQuery}`);
}
return dispatch(loadPhotos(photoCache[formattedQuery]));
}
dispatch(setLoading(true));
return api
.getImages(formattedQuery)
.then((response: any) => {
const body: ISearchResult = response.body;
dispatch(loadPhotos({ cachedAt: now, query: formattedQuery, ...body }));
})
.catch(e => {
// perhaps there should be an alert displayed to a user instead of
// logging to the console.
dispatch(setLoading(false));
console.error(e);
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.