You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
7.7 KiB
153 lines
7.7 KiB
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 _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; } |
|
|
|
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 _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; } |
|
|
|
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; } |
|
|
|
import { FLUSH, PAUSE, PERSIST, PURGE, REHYDRATE, DEFAULT_VERSION } from './constants'; |
|
import autoMergeLevel1 from './stateReconciler/autoMergeLevel1'; |
|
import createPersistoid from './createPersistoid'; |
|
import defaultGetStoredState from './getStoredState'; |
|
import purgeStoredState from './purgeStoredState'; |
|
var DEFAULT_TIMEOUT = 5000; |
|
/* |
|
@TODO add validation / handling for: |
|
- persisting a reducer which has nested _persist |
|
- handling actions that fire before reydrate is called |
|
*/ |
|
|
|
export default function persistReducer(config, baseReducer) { |
|
if (process.env.NODE_ENV !== 'production') { |
|
if (!config) throw new Error('config is required for persistReducer'); |
|
if (!config.key) throw new Error('key is required in persistor config'); |
|
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'`"); |
|
} |
|
|
|
var version = config.version !== undefined ? config.version : DEFAULT_VERSION; |
|
var debug = config.debug || false; |
|
var stateReconciler = config.stateReconciler === undefined ? autoMergeLevel1 : config.stateReconciler; |
|
var getStoredState = config.getStoredState || defaultGetStoredState; |
|
var timeout = config.timeout !== undefined ? config.timeout : DEFAULT_TIMEOUT; |
|
var _persistoid = null; |
|
var _purge = false; |
|
var _paused = true; |
|
|
|
var conditionalUpdate = function conditionalUpdate(state) { |
|
// update the persistoid only if we are rehydrated and not paused |
|
state._persist.rehydrated && _persistoid && !_paused && _persistoid.update(state); |
|
return state; |
|
}; |
|
|
|
return function (state, action) { |
|
var _ref = state || {}, |
|
_persist = _ref._persist, |
|
rest = _objectWithoutProperties(_ref, ["_persist"]); // $FlowIgnore need to update State type |
|
|
|
|
|
var restState = rest; |
|
|
|
if (action.type === PERSIST) { |
|
var _sealed = false; |
|
|
|
var _rehydrate = function _rehydrate(payload, err) { |
|
// dev warning if we are already sealed |
|
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 |
|
|
|
if (!_sealed) { |
|
action.rehydrate(config.key, payload, err); |
|
_sealed = true; |
|
} |
|
}; |
|
|
|
timeout && setTimeout(function () { |
|
!_sealed && _rehydrate(undefined, new Error("redux-persist: persist timed out for persist key \"".concat(config.key, "\""))); |
|
}, timeout); // @NOTE PERSIST resumes if paused. |
|
|
|
_paused = false; // @NOTE only ever create persistoid once, ensure we call it at least once, even if _persist has already been set |
|
|
|
if (!_persistoid) _persistoid = createPersistoid(config); // @NOTE PERSIST can be called multiple times, noop after the first |
|
|
|
if (_persist) { |
|
// We still need to call the base reducer because there might be nested |
|
// uses of persistReducer which need to be aware of the PERSIST action |
|
return _objectSpread({}, baseReducer(restState, action), { |
|
_persist: _persist |
|
}); |
|
} |
|
|
|
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.'); |
|
action.register(config.key); |
|
getStoredState(config).then(function (restoredState) { |
|
var migrate = config.migrate || function (s, v) { |
|
return Promise.resolve(s); |
|
}; |
|
|
|
migrate(restoredState, version).then(function (migratedState) { |
|
_rehydrate(migratedState); |
|
}, function (migrateErr) { |
|
if (process.env.NODE_ENV !== 'production' && migrateErr) console.error('redux-persist: migration error', migrateErr); |
|
|
|
_rehydrate(undefined, migrateErr); |
|
}); |
|
}, function (err) { |
|
_rehydrate(undefined, err); |
|
}); |
|
return _objectSpread({}, baseReducer(restState, action), { |
|
_persist: { |
|
version: version, |
|
rehydrated: false |
|
} |
|
}); |
|
} else if (action.type === PURGE) { |
|
_purge = true; |
|
action.result(purgeStoredState(config)); |
|
return _objectSpread({}, baseReducer(restState, action), { |
|
_persist: _persist |
|
}); |
|
} else if (action.type === FLUSH) { |
|
action.result(_persistoid && _persistoid.flush()); |
|
return _objectSpread({}, baseReducer(restState, action), { |
|
_persist: _persist |
|
}); |
|
} else if (action.type === PAUSE) { |
|
_paused = true; |
|
} else if (action.type === REHYDRATE) { |
|
// noop on restState if purging |
|
if (_purge) return _objectSpread({}, restState, { |
|
_persist: _objectSpread({}, _persist, { |
|
rehydrated: true |
|
}) // @NOTE if key does not match, will continue to default else below |
|
|
|
}); |
|
|
|
if (action.key === config.key) { |
|
var reducedState = baseReducer(restState, action); |
|
var inboundState = action.payload; // only reconcile state if stateReconciler and inboundState are both defined |
|
|
|
var reconciledRest = stateReconciler !== false && inboundState !== undefined ? stateReconciler(inboundState, state, reducedState, config) : reducedState; |
|
|
|
var _newState = _objectSpread({}, reconciledRest, { |
|
_persist: _objectSpread({}, _persist, { |
|
rehydrated: true |
|
}) |
|
}); |
|
|
|
return conditionalUpdate(_newState); |
|
} |
|
} // if we have not already handled PERSIST, straight passthrough |
|
|
|
|
|
if (!_persist) return baseReducer(state, action); // run base reducer: |
|
// is state modified ? return original : return updated |
|
|
|
var newState = baseReducer(restState, action); |
|
if (newState === restState) return state; |
|
return conditionalUpdate(_objectSpread({}, newState, { |
|
_persist: _persist |
|
})); |
|
}; |
|
} |