react-tienda
Version:
React Tienda is a lightweight and intuitive global state management library for React, designed to easily share state across components with minimal setup.
140 lines (136 loc) • 5.41 kB
JavaScript
import { isObject, EventBus, includeKeys, joinObjects, has } from 'hd-utils';
import React, { useState, useCallback, useMemo } from 'react';
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function (n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
}
return n;
}, _extends.apply(null, arguments);
}
// In case the react version doesn't support useLayoutEffect
var useEffect = React.useLayoutEffect || React.useEffect;
function newObjWithKeys(keyList, mappedToObj) {
var newObj = {};
keyList.forEach(function (key) {
newObj[key] = mappedToObj[key];
});
return newObj;
}
var UPDATE_STATE_EVENT = 'UPDATE_STATE';
/**
* @description Will create a global store where state is shared among components that use the returned hook that can be used to set and get the state.
* @advanced You can enter the global (store scope) state using useStore.getGlobalState() or set the global state useStore.setGlobalState
* @author https://github.com/AhmadHddad
* @example export const useStore = createGlobalStore({a:1, b:2});
* @returns hook that is used to connect the component with the store.
* its its really recommended to specify the used store keys in the returned hook (as list of strings) to reduce the component rerendering.
* @example const Component = () => {
* const [storeState, setStoreState] = useStore(["a"]);
*
* return <button onClick={()=> setStoreState({a:3})}>Click me</button>
* }
*/
function createGlobalStore(initState, actions, storeConfigs) {
if (initState === void 0) {
initState = {};
}
if (actions === void 0) {
actions = {};
}
if (!isObject(initState)) {
throw new Error('Error: The initial state should be of type object');
}
var oldState = _extends({}, initState);
var storeState = _extends({}, initState);
var storeBus = new EventBus();
function useStore(select, hookConfigs) {
var _ref = hookConfigs || {},
shallowCompareOnSetState = _ref.shallowCompareOnSetState;
var _useState = useState(Array.isArray(select) ? newObjWithKeys(select, storeState) : storeState),
componentState = _useState[0],
setComponentState = _useState[1];
var shallowCompare = shallowCompareOnSetState != null ? shallowCompareOnSetState : storeConfigs == null ? void 0 : storeConfigs.shallowCompareOnSetState;
useEffect(function () {
var handleStateChange = function handleStateChange(updatedState) {
var newState = {};
for (var key in updatedState) {
if (has(componentState, key)) {
newState[key] = updatedState[key];
}
}
if (Object.keys(newState).length === 0) {
return;
}
storeState = joinObjects(storeState, newState);
setComponentState(function (prev) {
return _extends({}, prev, newState);
});
};
storeBus.subscribe(UPDATE_STATE_EVENT, handleStateChange);
return function () {
storeBus.unsubscribe(UPDATE_STATE_EVENT, handleStateChange);
};
}, []);
var updateState = useCallback(function (newState, options) {
if (typeof newState === 'function') {
var updatedState = newState(componentState);
if (!isObject(updatedState)) {
throw new Error('Error: The return type should be object with the new state');
}
storeBus.publish(UPDATE_STATE_EVENT, updatedState);
} else {
if (!isObject(newState)) {
throw new Error('Error: The updated state should be of type object or function');
}
var isEqual = (options == null ? void 0 : options.comparer) && options.comparer(componentState, newState);
if (isEqual) {
return;
}
if (shallowCompare) {
var keyList = select || Object.keys(componentState);
keyList.forEach(function (key) {
if (componentState[key] === newState[key]) {
delete newState[key];
}
});
}
storeBus.publish(UPDATE_STATE_EVENT, newState);
}
}, [componentState, select, shallowCompare]);
var resetStoreState = useCallback(function (all) {
var newState = !all && select ? includeKeys(oldState, select) : oldState;
storeBus.publish(UPDATE_STATE_EVENT, newState);
}, [select]);
var actionsMemo = useMemo(function () {
var newActions = {};
for (var actionKey in actions) {
if (Object.prototype.hasOwnProperty.call(actions, actionKey)) {
var action = actions[actionKey];
newActions[actionKey] = action(storeState, updateState);
}
}
return newActions;
}, [actions, updateState]);
return [componentState, useMemo(function () {
return {
setStoreState: updateState,
actions: actionsMemo,
resetStoreState: resetStoreState
};
}, [actionsMemo, resetStoreState])];
}
useStore.setGlobalState = function (newState, options) {
if (options != null && options.override) {
storeState = joinObjects(storeState, newState);
}
storeBus.publish(UPDATE_STATE_EVENT, newState);
};
useStore.getGlobalState = function () {
return storeState;
};
return useStore;
}
export default createGlobalStore;
//# sourceMappingURL=react-tienda.esm.js.map