zippy-store
Version:
A lightweight and versatile global state management solution designed for seamless integration in both JavaScript and React applications. Provides a simple and efficient way to manage shared state across components and even in non-React JavaScript environ
156 lines • 7.08 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const isReactNative = () => {
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
};
class StoreManager {
constructor() {
this.stores = {}; // Use a more specific type
this.persistStoreKeys = {};
this.getStore = (storeKey) => {
return this.stores[storeKey]; // Type assertion for safety
};
this.getState = (storeKey) => {
const store = this.getStore(storeKey);
return store ? JSON.parse(JSON.stringify(store.state)) : undefined; // Deep copy
};
this.getActions = (storeKey) => {
var _a;
const actions = (_a = this.stores[storeKey]) === null || _a === void 0 ? void 0 : _a.actions;
return Object.assign({}, actions);
};
this.setState = (storeKey, newStateCb) => __awaiter(this, void 0, void 0, function* () {
const store = this.getStore(storeKey);
if (!store) {
throw new Error(`Store with key "${storeKey}" not initialized.`);
}
const state = this.getState(storeKey); // Assertion is safe here as getState does deep copy
const storeUpdates = typeof newStateCb === 'function' ? yield newStateCb(state) : newStateCb;
store.state = Object.assign(Object.assign({}, state), storeUpdates);
this.notifySubscribers(storeKey);
if (this.persistStoreKeys[storeKey]) {
this.setLocalStorageItem(storeKey, store.state);
}
});
this.notifySubscribers = (storeKey) => {
const store = this.getStore(storeKey);
if (!store) {
return;
}
for (const symbol of Object.getOwnPropertySymbols(store.subscribers)) {
if (typeof symbol === 'symbol') { // Ensure it's a symbol
store.subscribers[symbol](this.getState(storeKey));
}
}
};
this.setStateCreator = (storeKey) => {
return (cb) => this.setState(storeKey, (state) => typeof cb === 'function' ? cb(state) : cb);
};
// private getAsyncLocalStorageItem = async <T extends State>(key: string = '', initialState: T) => {
// try {
// const AsyncStorage = (await import('@react-native-async-storage/async-storage')).default;
// const value = await AsyncStorage.getItem(key);
// const localStorageState = value ? JSON.parse(value) : null;
// if (localStorageState) {
// this.setState(key, localStorageState)
// }
// } catch (e) {
// console.error(e);
// return null;
// }
// }
// private setAsyncLocalStorageItem = async <T extends State>(key: string, value: T) => {
// try {
// const AsyncStorage = (await import('@react-native-async-storage/async-storage')).default;
// const stringValue = JSON.stringify(value);
// await AsyncStorage.setItem(key, stringValue);
// } catch (e) {
// console.error(e);
// }
// }
this.getLocalStorageItem = (key = '', initialState) => {
try {
if (!isReactNative()) {
const localStorageState = JSON.parse(localStorage.getItem(key) || 'null');
return localStorageState ? localStorageState : initialState;
}
else {
// this.getAsyncLocalStorageItem(key, initialState); // async storage
return null;
}
}
catch (e) {
console.error(e);
return null;
}
};
this.setLocalStorageItem = (key, value) => __awaiter(this, void 0, void 0, function* () {
try {
const stringValue = JSON.stringify(value);
if (!isReactNative()) {
localStorage.setItem(key, stringValue);
}
else {
// this.setAsyncLocalStorageItem(key, value); // async storage
}
}
catch (e) {
console.error(e);
}
});
this.store = {
createStore: (storeKey, stateAndActionsFn, persist = false) => {
this.persistStoreKeys[storeKey] = persist;
let store = this.getStore(storeKey);
if (!store) {
const initialStateAndActions = stateAndActionsFn(this.setStateCreator(storeKey), () => this.getState(storeKey));
const state = {};
const actions = {};
for (const key in initialStateAndActions) {
if (typeof initialStateAndActions[key] !== "function") {
state[key] = initialStateAndActions[key];
}
else {
actions[key] = initialStateAndActions[key];
}
}
let localStorageState = undefined;
if (persist) {
localStorageState = this.getLocalStorageItem(storeKey, state);
}
store = {
state: localStorageState || state,
subscribers: {},
actions: actions,
};
this.stores[storeKey] = store; // Store the created store
}
return { dispatch: Object.assign({}, store.actions) }; // Return a copy to prevent direct mutation
},
setState: this.setState,
getState: this.getState,
dispatch: this.getActions,
subscribe: (key, cb) => {
const store = this.getStore(key);
if (!store) {
throw new Error(`Store with key "${key}" not initialized.`);
}
const uuid = Symbol();
store.subscribers[uuid] = cb;
return () => {
delete store.subscribers[uuid];
};
},
};
}
}
const storeManagerInstance = new StoreManager();
export default storeManagerInstance.store;
//# sourceMappingURL=store.js.map