UNPKG

@rootstrap/redux-tools

Version:

Redux tools we use in both react bases

215 lines (180 loc) 5.35 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var imm = _interopDefault(require('immer')); var reactRedux = require('react-redux'); /** * Makes action creators * * @param {string} type - Dispatched actions type * @return {function} Action creator * * @example * const loginSuccess = createAction('LOGIN_SUCCESS') */ var createAction = type => { const action = payload => ({ type, payload, }); action.toString = () => type; return action }; const NOT_STARTED = 'NOT_STARTED'; const LOADING = 'LOADING'; const SUCCESS = 'SUCCESS'; const ERROR = 'ERROR'; const REQUEST = 'REQUEST'; const RESET = 'RESET'; /** * Creates different actions creators * * @param {string} actionName - Action name, will be used as a prefix for the action creators. * @param {function} thunk - This is your async thunk, receives all forwarded params and `dispatch` and `getState` as params * * @returns {ActionCreator} Action that can be dispatched to start the async thunk, can also be * deconstructed to get request, error, and success action creators (can be used as keys in reducer) * * @example * export const getProfile = createActionWithThunk( * 'LOGIN', * user => userService.login(user), * ); * export const { success, error } = getProfile; */ var createThunk = (actionName, thunk) => { const request = createAction(`${actionName}_${REQUEST}`); const error = createAction(`${actionName}_${ERROR}`); const success = createAction(`${actionName}_${SUCCESS}`); const reset = createAction(`${actionName}_${RESET}`); const action = (...params) => ({ success, error, thunk: (dispatch, getState) => thunk(...params, dispatch, getState), type: request.toString(), }); action.request = request; action.error = error; action.success = success; action.reset = reset; action.toString = () => actionName; return action }; /** * Reducer creator util * * @param initialState Reducer initial state * @param actionHandlers - An object with all the reducer handlers * * @return {function} A reducer ready to use in createStore * * @example * const myReducer = createReducer({}, { * [loginSuccess]: (state, action) => { * state.user = action.payload * } * }) */ var createReducer = (initialState, actionHandlers) => ( state = initialState, action, ) => imm(state, draft => actionHandlers[action.type] ? actionHandlers[action.type](draft, action) : state, ); const handleAction = (state, action) => { const { type, payload } = action; const matchesStart = /(.*)_REQUEST/.exec(type); const matchesError = /(.*)_ERROR/.exec(type); const matchesReset = /(.*)_RESET/.exec(type); const matchesSuccess = /(.*)_SUCCESS/.exec(type); let status = NOT_STARTED; let key = null; if (matchesStart) { const [, requestName] = matchesStart; key = requestName; status = LOADING; } else if (matchesReset) { const [, requestName] = matchesReset; key = requestName; status = NOT_STARTED; } else if (matchesError) { const [, requestName] = matchesError; key = requestName; status = ERROR; } else if (matchesSuccess) { const [, requestName] = matchesSuccess; key = requestName; status = SUCCESS; } if (key) state[key] = { status, error: matchesError ? payload : undefined }; return state }; var statusReducer = (state = {}, action) => imm(state, draft => handleAction(draft, action)); const id = item => item; const thunkMiddlewareCreator = ({ parseError = id, parseResponse = id, } = {}) => ({ dispatch, getState }) => next => async action => { next(action); const { thunk, success, error } = action; if (typeof thunk === 'function') { try { const response = await thunk(dispatch, getState); return dispatch(success(parseResponse(response))) } catch (err) { return dispatch(error(parseError(err))) } } }; const thunkMiddleware = thunkMiddlewareCreator(); thunkMiddleware.withConfig = thunkMiddlewareCreator; /** * useStatus hook * * @param {string} action Prefix for the action names * * @returns {object} Object with status and error keys * * @example * const { status, error } = useStatus(login) */ var useStatus = action => reactRedux.useSelector(({ statusReducer }) => { const { status, error } = statusReducer[action] || {}; return { status, error, } }); /** * useLoading hook * * @param {string} action Prefix for the action names * * @returns {boolean} Wether the action is loading * * @example * const isLoading = useStatus(getProfile) */ var useLoading = action => reactRedux.useSelector(({ statusReducer }) => { const { status } = statusReducer[action] || {}; return status === LOADING }); exports.ERROR = ERROR; exports.LOADING = LOADING; exports.NOT_STARTED = NOT_STARTED; exports.REQUEST = REQUEST; exports.RESET = RESET; exports.SUCCESS = SUCCESS; exports.createAction = createAction; exports.createReducer = createReducer; exports.createThunk = createThunk; exports.statusReducer = statusReducer; exports.thunkMiddleware = thunkMiddleware; exports.useLoading = useLoading; exports.useStatus = useStatus;