react-hookz
Version:
[](https://travis-ci.com/garywenneker/react-hookz) [ • 3.29 kB
text/typescript
export interface IHookzListener {
oldState: any;
run?: (state: any) => void;
}
export interface IHookzStore {
state: any;
actions?: any;
listeners: IHookzListener[];
setState?: (newState: any, afterUpdateCallback: any) => void;
}
function setState(store: IHookzStore, newState: any, afterUpdateCallback: any) {
store.state = { ...store.state, ...newState };
store.listeners.forEach((listener: IHookzListener) => {
if (listener.run) {
listener.run(store.state);
}
});
if (afterUpdateCallback) {
afterUpdateCallback();
}
}
function useCustom(
store: IHookzStore,
React: any,
mapState: any,
mapActions: any,
) {
const [, originalHook] = React.useState(Object.create(null));
const state = mapState ? mapState(store.state) : store.state;
const actions = React.useMemo(
() => (mapActions ? mapActions(store.actions) : store.actions),
[mapActions, store.actions],
);
React.useEffect(() => {
const newListener: IHookzListener = { oldState: {} };
newListener.run = mapState
? (newState: any) => {
const mappedState = mapState(newState);
if (mappedState !== newListener.oldState) {
newListener.oldState = mappedState;
originalHook(mappedState);
}
}
: originalHook;
store.listeners.push(newListener);
if (newListener.run) {
newListener.run(store.state);
}
return () => {
store.listeners = store.listeners.filter(
(listener) => (listener) !== newListener,
);
};
}, []); // eslint-disable-line
return [state, actions];
}
function associateActions({ store, actions }: { store: any; actions: any }) {
const associatedActions = {};
Object.keys(actions).forEach((key) => {
if (typeof actions[key] === "function") {
// @ts-ignore
associatedActions[key] = actions[key].bind(null, store);
}
if (typeof actions[key] === "object") {
// @ts-ignore
associatedActions[key] = associateActions({
actions: actions[key],
store,
});
}
});
return associatedActions;
}
/**
* React Global Hookz, a simple global state for React with the Hooks API in less than 1kb written in TypeScript
* @param React The imported namespace of your installed React version
* @param initialState Any state object you'd like to use
* @param actions An object of functions setting the state
* @param initializer Optional initialization function
* @see https://github.com/GaryWenneker/react-hookz
*/
const useHookz = (
React: any,
initialState: any,
actions: any,
initializer?: any,
) => {
const store: IHookzStore = { state: initialState, listeners: [] };
store.setState = setState.bind(null, store);
store.actions = associateActions({ store, actions });
if (initializer) {
initializer(store);
}
return useCustom.bind(null, store, React);
};
export default useHookz;