UNPKG

use-saga-reducer

Version:
311 lines (261 loc) 7.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var reduxSaga = require('redux-saga'); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } const SagaContext = React.createContext({}); /** * Passes values into `runSaga` of each decendent `useSagaReducer` call. * * Methods are merged with local values, context methods are run first. * Context value is merged with local value, local values will override * existing properties. * @param props Optional saga options */ const SagaProvider = (_ref) => { let { children } = _ref, props = _objectWithoutProperties(_ref, ["children"]); return React__default.createElement(SagaContext.Provider, { value: props, children: children }); }; function mergeVoidMethods(contextMethod, localMethod) { if (!contextMethod && !localMethod) { return; } if (contextMethod && !localMethod) { return contextMethod; } if (!contextMethod && localMethod) { return localMethod; } return (...args) => { contextMethod(...args); localMethod(...args); }; } function mergeSagaMonitors(contextMonitor, localMonitor) { if (!contextMonitor && !localMonitor) { return; } if (contextMonitor && !localMonitor) { return contextMonitor; } if (!contextMonitor && localMonitor) { return localMonitor; } const sagaMonitorKeys = ['actionDispatched', 'effectCancelled', 'effectRejected', 'effectResolved', 'effectTriggered', 'rootSagaStarted']; const combinedSagaMonitor = {}; for (const key of sagaMonitorKeys) { const method = mergeVoidMethods(contextMonitor[key], localMonitor[key]); if (method) { combinedSagaMonitor[key] = method; } } return combinedSagaMonitor; } function mergeEffectMiddlewares(contextMiddlewares, localMiddlewares) { if (!contextMiddlewares && !localMiddlewares) { return; } if (contextMiddlewares && !localMiddlewares) { return contextMiddlewares; } if (!contextMiddlewares && localMiddlewares) { return localMiddlewares; } return [...contextMiddlewares, ...localMiddlewares]; } /** * Create an saga, disconnected from redux with its own state and dispatch. * * @see https://github.com/azmenak/use-saga-reducer * @example * ``` * function* dataFetcher() { * try { * const data = yield call(API.fetchData) * yield put({type: 'FETCH_SUCCESS', payload: data}) * } catch (error) { * yield put({type: 'FETCH_ERROR'}) * } * } * * function* dataFetchingSaga() { * yield takeLatest('FETCH', dataFetcher) * } * * function reducer(state = {}, action) { * if (action.type === 'FETCH_SUCCESS') { * return action.payload * } * * return state * } * * //... * * const [state, dispatch] = useSagaReducer(saga, reducer) * ``` */ function useSagaReducer( /** * Saga method, called when the component mounts, must be a generator function. * Same as would be passed to reduxSaga.runSaga */ saga, /** * Reducer method, passed into React's `useReducer` method */ reducer, /** * Optional initalized argument, passed into React's `useReducer` method */ initializerArg, /** * Store initialized function, passed into React's `useReducer` method */ initializer, /** * Additional options passed into the `runSaga` method * * Supports: * ``` * sagaMonitor // each monitor will run context methods then local methods * onError // runs context method then local method * context // merges context values into local values * effectMiddlewares // combines with context middleswares, running context first * ``` * @see https://redux-saga.js.org/docs/api/#runsagaoptions-saga-args */ runSagaOptions) { const [state, reactDispatch] = React.useReducer(reducer, initializerArg, initializer); const stateRef = React.useRef(state); React.useEffect(() => { stateRef.current = state; }, [state]); const sagaIO = React.useMemo(() => { const channel = reduxSaga.stdChannel(); const dispatch = action => { reactDispatch(action); Promise.resolve().then(() => { channel.put(action); }); }; const getState = () => stateRef.current; return { channel, dispatch, getState }; }, []); const sagaContext = React.useContext(SagaContext); React.useEffect(() => { const options = runSagaOptions || {}; const context = _objectSpread2({}, sagaContext.context, {}, options.context); const sagaMonitor = mergeSagaMonitors(sagaContext.sagaMonitor, options.sagaMonitor); const onError = mergeVoidMethods(sagaContext.onError, options.onError); const effectMiddlewares = mergeEffectMiddlewares(sagaContext.effectMiddlewares, options.effectMiddlewares); const sagaOptions = _objectSpread2({}, sagaIO, { context, sagaMonitor, onError, effectMiddlewares }); const task = reduxSaga.runSaga(sagaOptions, saga); return () => { task.cancel(); }; }, []); return [state, sagaIO.dispatch]; } /** * Helper function to create custom redux-saga effects * @param type unique type string * @param payload any object */ function makeCustomEffect(type, payload) { return { '@@redux-saga/custom': true, combinator: false, type, payload }; } exports.SagaProvider = SagaProvider; exports.default = useSagaReducer; exports.makeCustomEffect = makeCustomEffect; exports.useSagaReducer = useSagaReducer; //# sourceMappingURL=index.js.map