Skip to content

Instantly share code, notes, and snippets.

@bpander
Created September 9, 2019 20:44
Show Gist options
  • Save bpander/a3e6dcc536af6c4fc38abf7d5d2862ed to your computer and use it in GitHub Desktop.
Save bpander/a3e6dcc536af6c4fc38abf7d5d2862ed to your computer and use it in GitHub Desktop.
import { createReducer } from '@sws/lib/createReducer';
import { ThunkAction } from 'redux-thunk';
import { AnyAction } from 'redux';
// ThingService.ts
interface Thing { id: string; name: string }
class ThingService {
static async fetch(thingId: string) {
/* api call */
const thing: Thing = { id: '1', name: 'thing 1' };
return thing;
}
static async update(thing: Thing) {
/* api call */
return thing;
}
static async fetchAll() {
return [];
}
}
// thunk util file
type FetchState =
| { status: 'idle' }
| { status: 'pending' }
| { status: 'resolved'; timestamp: number }
| { status: 'rejected'; error: Error }
// const createThunk = /* ... */;
// const callThunkIfNeeded = /* ... */;
// ThingDuck.ts
interface ThingState {
cache: Record<string, Thing>;
fetchThingState: FetchState;
updateThingState: FetchState;
}
const initialState: ThingState = {
cache: {},
fetchThingState: { status: 'idle' },
updateThingState: { status: 'idle' },
};
const { update, reducer } = createReducer('thing/UPDATE', initialState);
export const thingReducer = reducer;
const getSlice = (rootState: any): ThingState => rootState.thing;
const fetchThingVanilla = (thingId: string): ThunkAction<void, {}, {}, AnyAction> => async (dispatch, getState) => {
dispatch(update({ fetchThingState: { status: 'pending' } }));
try {
const thing = await ThingService.fetch(thingId);
dispatch(update({
fetchThingState: { status: 'resolved', timestamp: Date.now() },
cache: { ...getSlice(getState()).cache, [thing.id]: thing },
}));
} catch (error) {
dispatch(update({ fetchThingState: { status: 'rejected', error } }));
}
};
const updateInCache = (thing: Thing) => (dispatch, getState) => {
dispatch(update({ cache: { ...getSlice(getState()).cache, [thing.id]: thing } }));
};
export const fetchThing = createThunk(
ThingService.fetch,
thing => updateInCache(thing),
fetchThingState => update({ fetchThingState }), /* optional */
);
export const updateThing = createThunk(ThingService.update, updateInCache);
// export const fetchThingIfNeeded = memoizeThunk(fetchThing, state => {
// const thingState = getSlice(state);
// if (thingState.fetchThingState.status === 'rejected') {
// return true;
// }
// if (!isEqual(args, thingState.fetchThingState.args)) {
// return true;
// }
// if (thingState.fetchThingState.status === 'pending') {
// return false;
// }
// return maxAge(thingState.fetchThingState, 1000 * 60 * 60);
// });
export const fetchThingIfNeeded = memoizeThunk(
fetchThing,
state => getSlice(state).fetchThingState,
1000 * 60 * 60, /* optional */
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment