redux-persist-2
Version:
persist and rehydrate redux stores
208 lines (170 loc) • 6.63 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _forEach2 = require('lodash/forEach');
var _forEach3 = _interopRequireDefault(_forEach2);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.default = createPersistor;
var _constants = require('./constants');
var constants = _interopRequireWildcard(_constants);
var _asyncLocalStorage = require('./defaults/asyncLocalStorage');
var _asyncLocalStorage2 = _interopRequireDefault(_asyncLocalStorage);
var _jsonStringifySafe = require('json-stringify-safe');
var _jsonStringifySafe2 = _interopRequireDefault(_jsonStringifySafe);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createPersistor(store, config) {
// defaults
var lastStateInit = config.lastStateInit || {};
var stateIterator = config.stateIterator || defaultStateIterator;
var stateGetter = config.stateGetter || defaultStateGetter;
var stateSetter = config.stateSetter || defaultStateSetter;
var serialize = config.serialize || defaultSerialize;
var deserialize = config.deserialize || defaultDeserialize;
var blacklist = config.blacklist || [];
var whitelist = config.whitelist || false;
var transforms = config.transforms || [];
var debounce = config.debounce || false;
var storage = config.storage || (0, _asyncLocalStorage2.default)('local');
// fallback getAllKeys to `keys` if present (LocalForage compatability)
if (storage.keys && !storage.getAllKeys) storage = _extends({}, storage, { getAllKeys: storage.keys });
// initialize stateful values
var lastState = lastStateInit;
var paused = false;
var purgeMode = false;
var storesToProcess = [];
var timeIterator = null;
store.subscribe(function () {
if (paused) return;
var state = store.getState();
stateIterator(state, function (subState, key) {
if (!passWhitelistBlacklist(key)) return;
if (stateGetter(lastState, key) === stateGetter(state, key)) return;
if (storesToProcess.indexOf(key) !== -1) return;
storesToProcess.push(key);
});
// time iterator (read: debounce)
if (timeIterator === null) {
timeIterator = setInterval(function () {
if (storesToProcess.length === 0) {
clearInterval(timeIterator);
timeIterator = null;
return;
}
var key = storesToProcess[0];
var storageKey = createStorageKey(key);
var endState = transforms.reduce(function (subState, transformer) {
return transformer.in(subState, key);
}, stateGetter(store.getState(), key));
if (typeof endState !== 'undefined') storage.setItem(storageKey, serialize(endState), warnIfSetError(key));
storesToProcess.shift();
}, debounce);
}
lastState = state;
});
function passWhitelistBlacklist(key) {
if (whitelist && whitelist.indexOf(key) === -1) return false;
if (blacklist.indexOf(key) !== -1) return false;
return true;
}
function adhocRehydrate(incoming) {
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var state = {};
if (options.serial) {
(0, _forEach3.default)(incoming, function (subState, key) {
try {
var data = deserialize(subState);
var value = transforms.reduceRight(function (interState, transformer) {
return transformer.out(interState, key);
}, data);
state = stateSetter(state, key, value);
} catch (err) {
if (process.env.NODE_ENV !== 'production') console.warn('Error rehydrating data for key "' + key + '"', subState, err);
}
});
} else state = incoming;
store.dispatch(rehydrateAction(state));
return state;
}
function purge(keys) {
if (typeof keys === 'undefined') {
purgeAll();
} else {
purgeMode = keys;
(0, _forEach3.default)(keys, function (key) {
storage.removeItem(createStorageKey(key), warnIfRemoveError(key));
});
}
}
function purgeAll() {
purgeMode = '*';
storage.getAllKeys(function (err, allKeys) {
if (err && process.env.NODE_ENV !== 'production') {
console.warn('Error in storage.getAllKeys');
}
purge(allKeys.filter(function (key) {
return key.indexOf(constants.keyPrefix) === 0;
}).map(function (key) {
return key.slice(constants.keyPrefix.length);
}));
});
}
// return `persistor`
return {
rehydrate: adhocRehydrate,
pause: function pause() {
paused = true;
},
resume: function resume() {
paused = false;
},
purge: purge,
purgeAll: purgeAll,
_getPurgeMode: function _getPurgeMode() {
return purgeMode;
}
};
}
function warnIfRemoveError(key) {
return function removeError(err) {
if (err && process.env.NODE_ENV !== 'production') {
console.warn('Error storing data for key:', key, err);
}
};
}
function warnIfSetError(key) {
return function setError(err) {
if (err && process.env.NODE_ENV !== 'production') {
console.warn('Error storing data for key:', key, err);
}
};
}
function createStorageKey(key) {
return constants.keyPrefix + key;
}
function defaultSerialize(data) {
return (0, _jsonStringifySafe2.default)(data, null, null, function (k, v) {
if (process.env.NODE_ENV !== 'production') return null;
throw new Error('\n redux-persist: cannot process cyclical state.\n Consider changing your state structure to have no cycles.\n Alternatively blacklist the corresponding reducer key.\n Cycle encounted at key "' + k + '" with value "' + v + '".\n ');
});
}
function defaultDeserialize(serial) {
return JSON.parse(serial);
}
function rehydrateAction(data) {
return {
type: constants.REHYDRATE,
payload: data
};
}
function defaultStateIterator(collection, callback) {
return (0, _forEach3.default)(collection, callback);
}
function defaultStateGetter(state, key) {
return state[key];
}
function defaultStateSetter(state, key, value) {
state[key] = value;
return state;
}