Skip to content

Commit

Permalink
feat(manager): add 'setDispatch' method
Browse files Browse the repository at this point in the history
catch store's dispatch for internal use, like dispatching and action when injecting a reducer
instead of calling store.dispatch whenever is needed

#43
  • Loading branch information
aneurysmjs committed Dec 1, 2019
1 parent 5f9395f commit eb70aa9
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 9 deletions.
20 changes: 13 additions & 7 deletions src/app/store/config/alienStore/manager.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnyAction } from 'redux';
import { createStore, AnyAction } from 'redux';

import manager from './manager';

Expand All @@ -10,19 +10,14 @@ type AlienState = {
cart: CartType;
};

const preloadedState: AlienState = {
cart: {
quantity: 30,
},
};

describe('manager', () => {
it('should return an alienManager', () => {
const alienManager = manager();
expect(alienManager).toHaveProperty('getReducerMap');
expect(alienManager).toHaveProperty('injectReducers');
expect(alienManager).toHaveProperty('removeReducers');
expect(alienManager).toHaveProperty('rootReducer');
expect(alienManager).toHaveProperty('setDispatch');
});

describe('getReducerMap', () => {
Expand Down Expand Up @@ -88,4 +83,15 @@ describe('manager', () => {
});
});
});

describe('setDispatch', () => {
it('should set a Redux dispatcher for internal use', () => {
const store = createStore(() => {});
const alienManager = manager();
const setDispatchSpy = jest.spyOn(alienManager, 'setDispatch');

alienManager.setDispatch(store.dispatch);
expect(setDispatchSpy).toHaveBeenCalledWith(store.dispatch);
});
});
});
17 changes: 15 additions & 2 deletions src/app/store/config/alienStore/manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/ban-ts-ignore */
import { combineReducers, Reducer, AnyAction } from 'redux';
import { combineReducers, Reducer, AnyAction, Dispatch } from 'redux';

// get the return value if T is a function
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -12,26 +12,35 @@ type FullStoreShape<T> = {

type ReducerMapper<U> = Partial<{ [K in keyof Partial<U>]: Reducer<U[K]> }>;

export interface AlienManager<R = any> {
export interface AlienManager<R = {}> {
getReducerMap: () => ReducerMapper<FullStoreShape<R>>;
injectReducers: (key: string, reducer: Reducer) => Reducer | void;
removeReducers: (key: string) => void;
rootReducer: Reducer;
setDispatch: (storeDispatch: Dispatch<AnyAction>) => void;
}

type AlienDispatch = Dispatch<AnyAction> | null;

export default function manager<State>(initialReducers?: State): AlienManager<State> {
type StoreShape = FullStoreShape<State>;

type ReducerMap = ReducerMapper<StoreShape>;

const fallback = (): {} => ({});

let dispatch: AlienDispatch = null;

const reducers: ReducerMap = initialReducers ? { ...initialReducers } : {};
// @ts-ignore "combineReducers" doesn't have that overload match
let combinedReducer = initialReducers ? combineReducers(reducers) : fallback;

let keysToRemove: Array<string> = [];

function setDispatch(storeDispatch: Dispatch<AnyAction>): void {
dispatch = storeDispatch;
}

function getReducerMap(): ReducerMap {
return reducers;
}
Expand All @@ -44,6 +53,9 @@ export default function manager<State>(initialReducers?: State): AlienManager<St
reducers[key] = reducer;
// @ts-ignore "combineReducers" doesn't have that overload match
combinedReducer = combineReducers(reducers);
if (dispatch) {
dispatch({ type: '@@ALIEN_STORE/RELOAD' });
}
}

function removeReducers(key: string): void {
Expand Down Expand Up @@ -79,5 +91,6 @@ export default function manager<State>(initialReducers?: State): AlienManager<St
injectReducers,
removeReducers,
rootReducer,
setDispatch,
};
}

0 comments on commit eb70aa9

Please sign in to comment.