@wolf-tp/react-native-boilerplate
Version:
React Native Template
171 lines (153 loc) • 4.89 kB
text/typescript
import { Action, Dispatch, Middleware } from '@reduxjs/toolkit';
import { onCheckType } from '../method/index';
export type Listener = (action: Action) => void;
type ActionListenerContainer = {
action: string;
listener: Listener;
};
const _subscribedBefore: Listener[] = [];
const _subscribedAfter: Listener[] = [];
const _actionsSubscribedBefore: ActionListenerContainer[] = [];
const _actionsSubscribedAfter: ActionListenerContainer[] = [];
const _subscribe = (listener: Listener, listenerContainer: Listener[]) => {
if (!onCheckType(listener, 'function')) {
throw new Error('Expected the listener to be a function.');
}
listenerContainer.push(listener);
return () => {
const index = listenerContainer.indexOf(listener);
listenerContainer.splice(index, 1);
};
};
export const subscribeBefore = (listener: Listener) => {
return _subscribe(listener, _subscribedBefore);
};
export const subscribeAfter = (listener: Listener) => {
return _subscribe(listener, _subscribedAfter);
};
const _subscribeAction = (
actionListenerContainer: ActionListenerContainer,
listenerContainer: ActionListenerContainer[],
) => {
if (!onCheckType(actionListenerContainer.action, 'string')) {
throw new Error('Expected the action to be a string.');
}
if (!onCheckType(actionListenerContainer.listener, 'function')) {
throw new Error('Expected the listener to be a function.');
}
listenerContainer.push(actionListenerContainer);
return () => {
const index = listenerContainer.indexOf(actionListenerContainer);
listenerContainer.splice(index, 1);
};
};
export const subscribeActionBefore = (action: string, listener: Listener) => {
const actionListenerContainer = { action, listener };
return _subscribeAction(actionListenerContainer, _actionsSubscribedBefore);
};
export const subscribeActionAfter = (action: string, listener: Listener) => {
const actionListenerContainer = { action, listener };
return _subscribeAction(actionListenerContainer, _actionsSubscribedAfter);
};
export const unsubscribeBefore = () => {
_subscribedBefore.length = 0;
};
export const unsubscribeActionsBefore = () => {
_actionsSubscribedBefore.length = 0;
};
export const unsubscribeAfter = () => {
_subscribedAfter.length = 0;
};
export const unsubscribeActionsAfter = () => {
_actionsSubscribedAfter.length = 0;
};
export const unsubscribeAll = () => {
unsubscribeBefore();
unsubscribeActionsBefore();
unsubscribeAfter();
unsubscribeActionsAfter();
};
const _unsubscribeAction = (
listenerContainer: ActionListenerContainer[],
filterAction: string,
) => {
const filteredListenerContainer = listenerContainer.filter(
({ action }) => action !== filterAction,
);
listenerContainer.length = 0;
listenerContainer.push(...filteredListenerContainer);
};
export const unsubscribeActionBefore = (action: string) => {
_unsubscribeAction(_actionsSubscribedBefore, action);
};
export const unsubscribeActionAfter = (action: string) => {
_unsubscribeAction(_actionsSubscribedAfter, action);
};
export const unsubscribeActionAll = (action: string) => {
unsubscribeActionBefore(action);
unsubscribeActionAfter(action);
};
const _callListeners = (action: Action, listenerContainer: Listener[]) => {
for (let i = listenerContainer.length - 1; i >= 0; i--) {
const listener = listenerContainer[i];
if (typeof action === 'object') {
listener(action);
}
}
};
const _callActionListeners = (
action: Action,
listenerContainer: ActionListenerContainer[],
) => {
for (let i = listenerContainer.length - 1; i >= 0; i--) {
const listener = listenerContainer[i];
if (
action &&
onCheckType(action.type, 'string') &&
listener.action === action.type
) {
listener.listener(action);
}
}
};
export const subscribeActionMiddleware: Middleware =
() =>
(next: Dispatch) =>
<A extends Action>(action: A) => {
_callListeners(action, _subscribedBefore);
_callActionListeners(action, _actionsSubscribedBefore);
const result = next(action);
_callListeners(action, _subscribedAfter);
_callActionListeners(action, _actionsSubscribedAfter);
return result;
};
/**
* Usage
*
* useEffect(() => {
* const unsubscribe = subscribeAfter(action =>
* console.log(`Before state change action ${action.type}`),
* );
* return () => {
* unsubscribe();
* };
* }, []);
*
* useEffect(() => {
* const unsubscribe = subscribeActionBefore('MY_ACTION_TYPE', action =>
* console.log(`Before state change action MY_ACTION_TYPE`),
* );
* return () => {
* unsubscribe();
* };
* }, []);
*
* useEffect(() => {
* const unsubscribe = subscribeActionAfter('MY_ACTION_TYPE', action =>
* console.log(`After state change action MY_ACTION_TYPE`),
* );
* return () => {
* unsubscribe();
* };
* }, []);
*/