Skip to content

Instantly share code, notes, and snippets.

@artalar
Last active October 29, 2018 10:20
Show Gist options
  • Select an option

  • Save artalar/f99c5bd7ef96553286c060785104b215 to your computer and use it in GitHub Desktop.

Select an option

Save artalar/f99c5bd7ef96553286c060785104b215 to your computer and use it in GitHub Desktop.
const getAsyncType = (type, status) => `${type}_${status}`;
let index = 0;
export const getMasterActionCreator = description => {
const type = `${index++}__${description}`;
const reqType = getAsyncType(type, "REQUEST");
const respType = getAsyncType(type, "SUCCESS");
const errType = getAsyncType(type, "ERROR");
const masterActionCreator = (...params) => ({ params, type });
masterActionCreator.toString = () => type;
masterActionCreator.request = (...params) => ({ params, type: reqType });
masterActionCreator.request.toString = () => reqType;
masterActionCreator.response = (...params) => ({ params, type: respType });
masterActionCreator.response.toString = () => respType;
masterActionCreator.error = (...params) => ({ params, type: errType });
masterActionCreator.error.toString = () => errType;
return masterActionCreator;
};
export const createReducer = (handlers, initialState = {}) => (
state = initialState,
action
) =>
handlers.hasOwnProperty(action.type)
? handlers[action.type](state, ...action.params)
: state;
// handle middleware
export const handleWorkflow = workflow => store => next => action => {
next(action);
if (workflow.hasOwnProperty(action.type)) {
workflow[action](store, ...action.params);
}
};
export const createAsyncWorkflow = (
action,
onRequest,
onAction,
onResponse,
onError
) => ({
[action]: (store, ...params) =>
onAction
? store.dispatch(action.request(onAction(store, ...params)))
: store.dispatch(action.request(...params)),
[action.request]: async (store, ...params) => {
try {
const response = await onRequest(...params);
onResponse
? store.dispatch(action.response(onResponse(store, response)))
: store.dispatch(action.response(response));
} catch (error) {
onError
? store.dispatch(action.error(onError(store, error)))
: store.dispatch(action.error(error));
}
}
});
// actions.js
export const changeField = getMasterActionCreator("CHANGE_FIELD");
export const sendForm = getMasterActionCreator("SEND_FORM");
// reducer.js
const initialsState = {
loading: false,
values: localStorage.getItem("form") | {}
};
export const formReducer = createReducer(
{
[changeField]: (state, name, value) => ({
...state,
values: { ...values, [name]: value }
}),
[sendForm.request]: state => ({ ...state, loading: true }),
[sendForm.response]: state => ({ ...state, loading: false }),
[sendForm.error]: state => ({ ...state, loading: false })
},
initialsState
);
// component.js
function handleChange(event) {
this.props.dispatch(changeField(event.target.name, event.target.value));
}
function handleSubmit(event) {
event.preventDefault();
this.props.dispatch(sendForm());
}
// workflow.js
const workflow = {
[changeField]: (store, name, value) => {
/* debounced */ saveToLocalStorage("form", { name, value });
},
...createAsyncWorkflow(
sendForm, // action
formValues => api.sendForm(formValues), // request
store => store.getState().form.values, // prepare payload for request action
// <- paste here prepare payload for response action
// <- paste here prepare payload for error action
)
};
export const workflowMidleware = handleWorkflow(workflow);
// actions.js
const CHANGE_FIELD = "CHANGE_FIELD";
const SEND_FORM_REQUEST = "SEND_FORM_REQUEST";
const SEND_FORM_RESPONSE = "SEND_FORM_RESPONSE";
const SEND_FORM_ERROR = "SEND_FORM_ERROR";
export const changeField = payload => {
/* debounced */ saveToLocalStorage("form", { name, value });
return { type: CHANGE_FIELD, payload };
};
/*
!you still need redux-thunk for this!
*/
export const sendForm = () => async (dispatch, getState) => {
try {
dispatch({ type: SEND_FORM_REQUEST });
const response = api.sendForm(getState().form.values);
dispatch({ type: SEND_FORM_RESPONSE, payload: response });
} catch (error) {
dispatch({ type: SEND_FORM_ERROR, payload: response });
}
};
// reducer.js
const initialsState = {
loading: false,
values: localStorage.getItem("form") | {}
};
export const formReducer = (state = initialsState, action) => {
switch (action.type) {
case CHANGE_FIELD: {
const { name, value } = actions.payload;
return {
...state,
values: { ...values, [name]: value }
};
}
case SEND_FORM_REQUEST:
return { ...state, loading: true };
case SEND_FORM_RESPONSE:
return { ...state, loading: false };
case SEND_FORM_ERROR:
return { ...state, loading: false };
default:
return state;
}
};
// component.js
function handleChange(event) {
this.props.dispatch(changeField(event.target.name, event.target.value));
}
function handleSubmit(event) {
event.preventDefault();
this.props.dispatch(sendForm());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment