persistnsync
Version:
Zustand middleware to easily persist and sync Zustand state between tabs and windows
132 lines (131 loc) • 5.77 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.persistNSync = void 0;
exports.clearStorage = clearStorage;
var DEFAULT_INIT_DELAY = 100;
function getItem(options) {
var cookies = document.cookie.split("; ");
var cookie = cookies.find(function (c) { return c.startsWith(options.name); });
return (localStorage.getItem(options.name) ||
sessionStorage.getItem(options.name) ||
(cookie === null || cookie === void 0 ? void 0 : cookie.split("=")[1]));
}
function setItem(options, value) {
var storage = options.storage;
if (storage === "cookies") {
document.cookie = "".concat(options.name, "=").concat(value, "; max-age=31536000; SameSite=Strict;");
}
if (storage === "sessionStorage")
sessionStorage.setItem(options.name, value);
else
localStorage.setItem(options.name, value);
}
function clearStorage(name, storage) {
switch (storage || "localStorage") {
case "localStorage":
localStorage.removeItem(name);
break;
case "sessionStorage":
sessionStorage.removeItem(name);
break;
case "cookies":
document.cookie = "".concat(name, "=;expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=Strict;");
break;
default:
}
}
var persistNSync = function (stateCreator, options) { return function (set, get, store) {
/** avoid error during serverside render */
if (!globalThis.localStorage)
return stateCreator(set, get, store);
if (!options.storage)
options.storage = "localStorage";
/** timeout 0 is enough. timeout 100 is added to avoid server and client render content mismatch error */
var delay = options.initDelay === undefined ? DEFAULT_INIT_DELAY : options.initDelay;
setTimeout(function () {
var initialState = get();
var savedState = getItem(options);
if (savedState)
set(__assign(__assign({}, initialState), JSON.parse(savedState)));
}, delay);
var set_ = function (newStateOrPartialOrFunction, replace) {
var prevState = get();
// @ts-expect-error -- Zustand v5 introduced stricter type checking
set(newStateOrPartialOrFunction, replace);
var newState = get();
saveAndSync({ newState: newState, prevState: prevState, options: options });
};
window.addEventListener("storage", function (e) {
if (e.key === options.name)
set(__assign(__assign({}, get()), JSON.parse(e.newValue || "{}")));
});
return stateCreator(set_, get, store);
}; };
exports.persistNSync = persistNSync;
/** Encapsulate cache in closure */
var getKeysToPersistAndSyncMemoised = (function () {
var persistAndSyncKeysCache = {};
var getKeysToPersistAndSync = function (keys, options) {
var exclude = options.exclude, include = options.include;
var keysToInlcude = (include === null || include === void 0 ? void 0 : include.length)
? keys.filter(function (key) { return matchPatternOrKey(key, include); })
: keys;
var keysToPersistAndSync = keysToInlcude.filter(function (key) { return !matchPatternOrKey(key, exclude || []); });
return keysToPersistAndSync;
};
return function (keys, options) {
var cacheKey = JSON.stringify({ options: options, keys: keys });
if (!persistAndSyncKeysCache[cacheKey])
persistAndSyncKeysCache[cacheKey] = getKeysToPersistAndSync(keys, options);
return persistAndSyncKeysCache[cacheKey];
};
})();
function matchPatternOrKey(key, patterns) {
for (var _i = 0, patterns_1 = patterns; _i < patterns_1.length; _i++) {
var patternOrKey = patterns_1[_i];
if (typeof patternOrKey === "string" && key === patternOrKey)
return true;
else if (patternOrKey instanceof RegExp && patternOrKey.test(key))
return true;
}
return false;
}
function saveAndSync(_a) {
var _b, _c;
var newState = _a.newState, prevState = _a.prevState, options = _a.options;
if (newState.__persistNSyncOptions) {
var prevStorage = ((_b = prevState.__persistNSyncOptions) === null || _b === void 0 ? void 0 : _b.storage) || options.storage;
var newStorage = ((_c = newState.__persistNSyncOptions) === null || _c === void 0 ? void 0 : _c.storage) || options.storage;
if (prevStorage !== newStorage) {
var name_1 = prevState.__persistNSyncOptions.name || options.name;
clearStorage(name_1, prevStorage);
}
Object.assign(options, newState.__persistNSyncOptions);
}
/** temporarily support `regExpToIgnore` */
if (!options.exclude)
options.exclude = [];
if (options.regExpToIgnore)
options.exclude.push(options.regExpToIgnore);
/** end of temporarily support `regExpToIgnore` */
var keysToPersistAndSync = getKeysToPersistAndSyncMemoised(Object.keys(newState), options);
if (keysToPersistAndSync.length === 0)
return;
var stateToStore = {};
keysToPersistAndSync
.filter(function (key) { return prevState[key] !== newState[key]; }) // using only shallow equality
.forEach(function (key) { return (stateToStore[key] = newState[key]); });
if (Object.keys(stateToStore).length)
setItem(options, JSON.stringify(stateToStore));
}