state-pool
Version:
Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨
263 lines (262 loc) • 9.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createStore = void 0;
var State_1 = require("./State");
var notImplementedErrorMsg = [
"You must implement 'loadState' and 'saveState' to be able ",
'to save state to your preffered storage. E.g \n',
'store.persist({ \n',
' saveState: function(key, state, isInitialSet){/*Code to save state to your storage*/}, \n',
' loadState: function(key, noState){/*Code to load state from your storage*/} \n',
'}) \n'
].join("");
var Empty = /** @class */ (function () {
function Empty() {
}
return Empty;
}()); // Class for empty state/value
var EMPTY = new Empty();
var PersistentStorage = /** @class */ (function () {
function PersistentStorage() {
this.SHOULD_PERSIST_BY_DEFAULT = false;
}
PersistentStorage.prototype.loadState = function (key, noState) {
throw TypeError(notImplementedErrorMsg);
};
PersistentStorage.prototype.saveState = function (key, state, isInitialSet) {
throw TypeError(notImplementedErrorMsg);
};
return PersistentStorage;
}());
var Store = /** @class */ (function () {
function Store(storeInitializer) {
this.states = new Map();
this.subscribers = [];
this.persistentStorage = new PersistentStorage();
if (storeInitializer) {
if (typeof storeInitializer === "function") {
storeInitializer = storeInitializer();
}
for (var key in storeInitializer) {
if (storeInitializer.hasOwnProperty(key)) {
this.setState(key, storeInitializer[key]);
}
}
}
}
Store.prototype.subscribe = function (observer) {
var _this = this;
if (this.subscribers.indexOf(observer) === -1) {
// Subscribe a component to this store
this.subscribers.push(observer);
}
var unsubscribe = function () {
_this.subscribers = _this.subscribers.filter(function (subscriber) { return subscriber !== observer; });
};
return unsubscribe;
};
Store.prototype.onStoreUpdate = function (key, value) {
this.subscribers.forEach(function (subscriber) {
subscriber(key, value);
});
};
Store.prototype.persist = function (config) {
if (config.saveState) {
this.persistentStorage.saveState = config.saveState;
}
if (config.loadState) {
this.persistentStorage.loadState = config.loadState;
}
if (config.removeState) {
this.persistentStorage.removeState = config.removeState;
}
if (config.clear) {
this.persistentStorage.clear = config.clear;
}
if (config.PERSIST_ENTIRE_STORE) {
this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT = config.PERSIST_ENTIRE_STORE;
}
};
Store.prototype.setState = function (key, initialValue, _a) {
var _this = this;
var _b = _a === void 0 ? {} : _a, persist = _b.persist;
var shouldPersist = persist === undefined ?
this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT : persist;
var shouldSaveToPersistentStorage = false;
if (shouldPersist) {
// Try to load state from persistent storage
var savedState = this.persistentStorage.loadState(key, EMPTY);
if (savedState !== EMPTY) {
// We have a saved state, so we use it as the initialValue
initialValue = savedState;
}
else {
// We don't have a saved state so we have to set/save it
// Here we set this flag to true but we'll save later after creating a state successfully
shouldSaveToPersistentStorage = true;
}
}
var onStateChange = function (newValue) {
// Note key & persist variables depends on scope
_this.onStoreUpdate(key, newValue);
if (shouldPersist) {
_this.persistentStorage.saveState(key, newValue, false);
}
};
// Create a state
var state = (0, State_1.createState)(initialValue);
var unsubscribe = state.subscribe({
observer: onStateChange,
selector: function (st) { return st; }
});
var storeState = {
"state": state,
"unsubscribe": unsubscribe,
"persist": shouldPersist
};
// Add state to the store
this.states.set(key, storeState);
if (shouldSaveToPersistentStorage) {
// Saving state to persistent storage after we've created it successfully
this.persistentStorage.saveState(key, state.getValue(), true);
}
};
Store.prototype.getState = function (key, config) {
if (config === void 0) { config = {}; }
var defaultValue;
if (config.hasOwnProperty('default')) {
// Use has set default explicitly
defaultValue = config.default;
}
else {
// No default value
defaultValue = EMPTY;
}
// Get key based state
if (!this.has(key)) { // state is not found
if (defaultValue !== EMPTY) { // Default value is found
// Create a state and use defaultValue as the initial value
this.setState(key, defaultValue, // Make sure we don't pass EMPTY value
{ persist: config.persist });
}
else {
// state is not found and the default value is not specified
var errorMsg = [
"There is no state with the key '".concat(key, "', "),
"You are either trying to access a ",
"state that doesn't exist or it was deleted."
];
throw Error(errorMsg.join(""));
}
}
return this.states.get(key).state;
};
Store.prototype.has = function (key) {
// Check if we have a state in a store
return this.states.has(key);
};
Store.prototype.items = function () {
var storeItems = [];
this.states.forEach(function (storeState, key) {
storeItems.push([key, storeState.state.getValue(), storeState.persist]);
});
return storeItems;
};
Store.prototype.getStateValue = function (key, selector) {
var state = this.getState(key);
return state.getValue(selector);
};
Store.prototype.clear = function (fn) {
var _this = this;
// Copy store
var storeCopy = this.states;
// Clear store
this.states = new Map();
if (this.persistentStorage.clear) {
try {
this.persistentStorage.clear();
}
catch (error) {
// Ignore errors in clearing states
}
}
if (fn) {
// Run store re-initialization
fn();
}
storeCopy.forEach(function (oldState, key) {
// Unsubscribe from an old state
oldState.unsubscribe();
// Notify subscribers to a store that a state has been removed
if (_this.has(key)) {
var newState = _this.getState(key);
_this.onStoreUpdate(key, newState.getValue());
}
// Rerender all components using this state
oldState.state.refresh();
});
};
Store.prototype.remove = function (Statekey, fn) {
var _this = this;
var keys = [];
if (typeof Statekey === 'string') {
keys = [Statekey];
}
else {
keys = Statekey;
}
var StatesToRemove = new Map();
keys.forEach(function (key) {
// Copy state to remove from a store
StatesToRemove.set(key, _this.states.get(key));
// Remove state from a store
_this.states.delete(key);
if (StatesToRemove.get(key).persist && // Is state persisted
_this.persistentStorage.removeState // Is removeState Implemented
) {
try {
_this.persistentStorage.removeState(key);
}
catch (error) {
// Ignore error in removing state
}
}
});
if (fn) {
// Run state re-initialization
fn();
}
StatesToRemove.forEach(function (oldState, key) {
// Unsubscribe from an old state
oldState.unsubscribe();
// Notify subscribers to a store that a state has been removed
if (_this.has(key)) {
var newState = _this.getState(key);
_this.onStoreUpdate(key, newState.getValue());
}
// Rerender all components depending on this state
oldState.state.refresh();
});
};
Store.prototype.useState = function (key, config) {
if (config === void 0) { config = {}; }
var storeStateConfig = config;
var stateConfig = config;
var state = this.getState(key, storeStateConfig);
return state.useState(stateConfig);
};
Store.prototype.useReducer = function (reducer, key, config) {
if (config === void 0) { config = {}; }
var storeStateConfig = config;
var stateConfig = config;
var state = this.getState(key, storeStateConfig);
return state.useReducer(reducer, stateConfig);
};
return Store;
}());
exports.default = Store;
function createStore(storeInitializer) {
// Create a store for key based state
return new Store(storeInitializer);
}
exports.createStore = createStore;