persistReducer.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. 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; }
  2. function _objectSpread(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; }
  3. 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; }
  4. 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; }
  5. 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; }
  6. import { FLUSH, PAUSE, PERSIST, PURGE, REHYDRATE, DEFAULT_VERSION } from './constants';
  7. import autoMergeLevel1 from './stateReconciler/autoMergeLevel1';
  8. import createPersistoid from './createPersistoid';
  9. import defaultGetStoredState from './getStoredState';
  10. import purgeStoredState from './purgeStoredState';
  11. var DEFAULT_TIMEOUT = 5000;
  12. /*
  13. @TODO add validation / handling for:
  14. - persisting a reducer which has nested _persist
  15. - handling actions that fire before reydrate is called
  16. */
  17. export default function persistReducer(config, baseReducer) {
  18. if (process.env.NODE_ENV !== 'production') {
  19. if (!config) throw new Error('config is required for persistReducer');
  20. if (!config.key) throw new Error('key is required in persistor config');
  21. if (!config.storage) throw new Error("redux-persist: config.storage is required. Try using one of the provided storage engines `import storage from 'redux-persist/lib/storage'`");
  22. }
  23. var version = config.version !== undefined ? config.version : DEFAULT_VERSION;
  24. var debug = config.debug || false;
  25. var stateReconciler = config.stateReconciler === undefined ? autoMergeLevel1 : config.stateReconciler;
  26. var getStoredState = config.getStoredState || defaultGetStoredState;
  27. var timeout = config.timeout !== undefined ? config.timeout : DEFAULT_TIMEOUT;
  28. var _persistoid = null;
  29. var _purge = false;
  30. var _paused = true;
  31. var conditionalUpdate = function conditionalUpdate(state) {
  32. // update the persistoid only if we are rehydrated and not paused
  33. state._persist.rehydrated && _persistoid && !_paused && _persistoid.update(state);
  34. return state;
  35. };
  36. return function (state, action) {
  37. var _ref = state || {},
  38. _persist = _ref._persist,
  39. rest = _objectWithoutProperties(_ref, ["_persist"]); // $FlowIgnore need to update State type
  40. var restState = rest;
  41. if (action.type === PERSIST) {
  42. var _sealed = false;
  43. var _rehydrate = function _rehydrate(payload, err) {
  44. // dev warning if we are already sealed
  45. if (process.env.NODE_ENV !== 'production' && _sealed) console.error("redux-persist: rehydrate for \"".concat(config.key, "\" called after timeout."), payload, err); // only rehydrate if we are not already sealed
  46. if (!_sealed) {
  47. action.rehydrate(config.key, payload, err);
  48. _sealed = true;
  49. }
  50. };
  51. timeout && setTimeout(function () {
  52. !_sealed && _rehydrate(undefined, new Error("redux-persist: persist timed out for persist key \"".concat(config.key, "\"")));
  53. }, timeout); // @NOTE PERSIST resumes if paused.
  54. _paused = false; // @NOTE only ever create persistoid once, ensure we call it at least once, even if _persist has already been set
  55. if (!_persistoid) _persistoid = createPersistoid(config); // @NOTE PERSIST can be called multiple times, noop after the first
  56. if (_persist) {
  57. // We still need to call the base reducer because there might be nested
  58. // uses of persistReducer which need to be aware of the PERSIST action
  59. return _objectSpread({}, baseReducer(restState, action), {
  60. _persist: _persist
  61. });
  62. }
  63. if (typeof action.rehydrate !== 'function' || typeof action.register !== 'function') throw new Error('redux-persist: either rehydrate or register is not a function on the PERSIST action. This can happen if the action is being replayed. This is an unexplored use case, please open an issue and we will figure out a resolution.');
  64. action.register(config.key);
  65. getStoredState(config).then(function (restoredState) {
  66. var migrate = config.migrate || function (s, v) {
  67. return Promise.resolve(s);
  68. };
  69. migrate(restoredState, version).then(function (migratedState) {
  70. _rehydrate(migratedState);
  71. }, function (migrateErr) {
  72. if (process.env.NODE_ENV !== 'production' && migrateErr) console.error('redux-persist: migration error', migrateErr);
  73. _rehydrate(undefined, migrateErr);
  74. });
  75. }, function (err) {
  76. _rehydrate(undefined, err);
  77. });
  78. return _objectSpread({}, baseReducer(restState, action), {
  79. _persist: {
  80. version: version,
  81. rehydrated: false
  82. }
  83. });
  84. } else if (action.type === PURGE) {
  85. _purge = true;
  86. action.result(purgeStoredState(config));
  87. return _objectSpread({}, baseReducer(restState, action), {
  88. _persist: _persist
  89. });
  90. } else if (action.type === FLUSH) {
  91. action.result(_persistoid && _persistoid.flush());
  92. return _objectSpread({}, baseReducer(restState, action), {
  93. _persist: _persist
  94. });
  95. } else if (action.type === PAUSE) {
  96. _paused = true;
  97. } else if (action.type === REHYDRATE) {
  98. // noop on restState if purging
  99. if (_purge) return _objectSpread({}, restState, {
  100. _persist: _objectSpread({}, _persist, {
  101. rehydrated: true
  102. }) // @NOTE if key does not match, will continue to default else below
  103. });
  104. if (action.key === config.key) {
  105. var reducedState = baseReducer(restState, action);
  106. var inboundState = action.payload; // only reconcile state if stateReconciler and inboundState are both defined
  107. var reconciledRest = stateReconciler !== false && inboundState !== undefined ? stateReconciler(inboundState, state, reducedState, config) : reducedState;
  108. var _newState = _objectSpread({}, reconciledRest, {
  109. _persist: _objectSpread({}, _persist, {
  110. rehydrated: true
  111. })
  112. });
  113. return conditionalUpdate(_newState);
  114. }
  115. } // if we have not already handled PERSIST, straight passthrough
  116. if (!_persist) return baseReducer(state, action); // run base reducer:
  117. // is state modified ? return original : return updated
  118. var newState = baseReducer(restState, action);
  119. if (newState === restState) return state;
  120. return conditionalUpdate(_objectSpread({}, newState, {
  121. _persist: _persist
  122. }));
  123. };
  124. }