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.
 
 
 

127 lines
3.8 KiB

import { KEY_PREFIX, REHYDRATE } from './constants';
// @TODO remove once flow < 0.63 support is no longer required.
export default function createPersistoid(config) {
// defaults
var blacklist = config.blacklist || null;
var whitelist = config.whitelist || null;
var transforms = config.transforms || [];
var throttle = config.throttle || 0;
var storageKey = "".concat(config.keyPrefix !== undefined ? config.keyPrefix : KEY_PREFIX).concat(config.key);
var storage = config.storage;
var serialize;
if (config.serialize === false) {
serialize = function serialize(x) {
return x;
};
} else if (typeof config.serialize === 'function') {
serialize = config.serialize;
} else {
serialize = defaultSerialize;
}
var writeFailHandler = config.writeFailHandler || null; // initialize stateful values
var lastState = {};
var stagedState = {};
var keysToProcess = [];
var timeIterator = null;
var writePromise = null;
var update = function update(state) {
// add any changed keys to the queue
Object.keys(state).forEach(function (key) {
if (!passWhitelistBlacklist(key)) return; // is keyspace ignored? noop
if (lastState[key] === state[key]) return; // value unchanged? noop
if (keysToProcess.indexOf(key) !== -1) return; // is key already queued? noop
keysToProcess.push(key); // add key to queue
}); //if any key is missing in the new state which was present in the lastState,
//add it for processing too
Object.keys(lastState).forEach(function (key) {
if (state[key] === undefined && passWhitelistBlacklist(key) && keysToProcess.indexOf(key) === -1 && lastState[key] !== undefined) {
keysToProcess.push(key);
}
}); // start the time iterator if not running (read: throttle)
if (timeIterator === null) {
timeIterator = setInterval(processNextKey, throttle);
}
lastState = state;
};
function processNextKey() {
if (keysToProcess.length === 0) {
if (timeIterator) clearInterval(timeIterator);
timeIterator = null;
return;
}
var key = keysToProcess.shift();
var endState = transforms.reduce(function (subState, transformer) {
return transformer.in(subState, key, lastState);
}, lastState[key]);
if (endState !== undefined) {
try {
stagedState[key] = serialize(endState);
} catch (err) {
console.error('redux-persist/createPersistoid: error serializing state', err);
}
} else {
//if the endState is undefined, no need to persist the existing serialized content
delete stagedState[key];
}
if (keysToProcess.length === 0) {
writeStagedState();
}
}
function writeStagedState() {
// cleanup any removed keys just before write.
Object.keys(stagedState).forEach(function (key) {
if (lastState[key] === undefined) {
delete stagedState[key];
}
});
writePromise = storage.setItem(storageKey, serialize(stagedState)).catch(onWriteFail);
}
function passWhitelistBlacklist(key) {
if (whitelist && whitelist.indexOf(key) === -1 && key !== '_persist') return false;
if (blacklist && blacklist.indexOf(key) !== -1) return false;
return true;
}
function onWriteFail(err) {
// @TODO add fail handlers (typically storage full)
if (writeFailHandler) writeFailHandler(err);
if (err && process.env.NODE_ENV !== 'production') {
console.error('Error storing data', err);
}
}
var flush = function flush() {
while (keysToProcess.length !== 0) {
processNextKey();
}
return writePromise || Promise.resolve();
}; // return `persistoid`
return {
update: update,
flush: flush
};
} // @NOTE in the future this may be exposed via config
function defaultSerialize(data) {
return JSON.stringify(data);
}