Skip to content

Commit

Permalink
refactor(products): use payload-based action
Browse files Browse the repository at this point in the history
arrange apiMiddleware to match payload actions for fetchProducts reducer

improves #34, #35
  • Loading branch information
aneurysmjs committed Sep 23, 2019
1 parent bb198b7 commit c2bb484
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/app/store/config/enhancer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const devtools =
/* eslint-enable */
const composeEnhancers = devtools || compose;
// eslint-disable-next-line no-underscore-dangle
// $FlowFixMe
const enhancer: EnhancerType = composeEnhancers(applyMiddleware(...middlewares));

export default enhancer;
32 changes: 19 additions & 13 deletions src/app/store/config/middlewares/apiMiddleware/apiMiddleware.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable no-unused-vars */
// @flow strict
import type { Dispatch, Middleware } from 'redux';

Expand All @@ -8,18 +7,27 @@ import type { Actions, AsyncAction } from '@/store/types/Actions';
type ApiMiddlewareType = Middleware<State, Actions, Dispatch<AsyncAction>>;

const apiMiddleware: ApiMiddlewareType = ({ dispatch, getState }) => (next) => (action) => {
const {
types,
callAPI,
shouldCallAPI = (s = true) => s,
payload = {},
} = action;
let meta = {};

if (action.meta) {
meta = { ...action.meta };
}

if (!types) {
if (!action.meta && !meta.types) {
// Normal action: pass it on
return next(action);
}

const {
payload = {},
} = action;

const {
types,
callAPI,
shouldCallAPI = (s = true) => s,
} = meta;

if (
!Array.isArray(types)
|| types.length !== 3
Expand All @@ -40,22 +48,20 @@ const apiMiddleware: ApiMiddlewareType = ({ dispatch, getState }) => (next) => (
const [requestType, successType, failureType] = types;

dispatch({
...payload,
payload: { ...payload },
type: requestType,
});
// $FlowFixMe
return (async () => {
try {
const response = await callAPI();
return dispatch({
...payload,
response,
payload: { response },
type: successType,
});
} catch (error) {
return dispatch({
...payload,
error,
payload: { error },
type: failureType,
});
}
Expand Down
22 changes: 12 additions & 10 deletions src/app/store/modules/products/actions/fetchProducts.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ import { getProducts } from '@/store/modules/products/selectors';
export default function fetchProducts(query: string = ''): AsyncAction {
return {
type: ASYNC_ACTION_TYPE,
types: [
types.GET_PRODUCTS_REQUEST,
types.GET_PRODUCTS_SUCCESS,
types.GET_PRODUCTS_FAILURE,
],
callAPI: () => api.get<string, ProductsType>(query),
shouldCallAPI: (state) => {
const products = getProducts(state);
// $FlowFixMe - это не должно орать
return !products.length;
meta: {
types: [
types.GET_PRODUCTS_REQUEST,
types.GET_PRODUCTS_SUCCESS,
types.GET_PRODUCTS_FAILURE,
],
callAPI: () => api.get<string, ProductsType>(query),
shouldCallAPI: (state) => {
const products = getProducts(state);
// $FlowFixMe - это не должно орать
return !products.length;
},
},
};
}
8 changes: 5 additions & 3 deletions src/app/store/modules/products/reducers/products.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ export default createReducer<ProductsType, ProductActionType>(initialState, {
},
[GET_PRODUCTS_SUCCESS](state, action) {
const {
response: {
data,
payload: {
response: {
data,
},
},
} = action;
return {
Expand All @@ -35,7 +37,7 @@ export default createReducer<ProductsType, ProductActionType>(initialState, {
};
},
[GET_PRODUCTS_FAILURE](state, action) {
const { error } = action;
const { payload: { error } } = action;
return {
...state,
isLoading: false,
Expand Down
8 changes: 5 additions & 3 deletions src/app/store/types/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ export type Actions =

export type AsyncAction = {
type: string,
types?: Array<string>,
callAPI?: () => Promise<*>,
shouldCallAPI?: (State) => boolean,
payload?: *,
meta?: {
types: Array<string>,
callAPI: () => Promise<*>,
shouldCallAPI?: (State) => boolean,
}
};
7 changes: 2 additions & 5 deletions src/app/store/types/ProductsType.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// @flow strict
import type { Action } from 'redux';

import type { Response, ResponseError } from '@/store/types/CommonType';

export type ProductType = {
Expand All @@ -23,7 +21,6 @@ export type ProductsType = {
};

export type ProductActionType = {
...$Exact<Action<string>>,
...$Exact<Response<Array<ProductType>>>,
...$Exact<ResponseError>,
type: string,
payload: Response<Array<ProductType>> & ResponseError,
};

0 comments on commit c2bb484

Please sign in to comment.