core-native
Version:
A lightweight framework based on React Native + Redux + Redux Saga, in strict TypeScript.
153 lines • 4.54 kB
JavaScript
import { put } from "redux-saga/effects";
import { app } from "./app";
import { loadingAction } from "./reducer";
import { stringifyWithMask } from "./util/json";
/**
* A helper for ActionHandler functions (Saga)
*/
export function createActionHandlerDecorator(interceptor) {
return (target) => {
const descriptor = target.descriptor;
const fn = descriptor.value;
descriptor.value = function* (...args) {
const rootState = app.store.getState();
yield* interceptor(fn.bind(this, ...args), rootState);
};
return target;
};
}
/**
* A helper for regular functions
*/
export function createRegularDecorator(interceptor) {
return (target) => {
const descriptor = target.descriptor;
const fn = descriptor.value;
descriptor.value = function (...args) {
const rootState = app.store.getState();
interceptor(fn.bind(this, ...args), rootState);
};
return target;
};
}
/**
* To mark state.loading[identifier] during Saga execution
*/
export function Loading(identifier = "global") {
return createActionHandlerDecorator(function* (handler) {
try {
yield put(loadingAction(true, identifier));
yield* handler();
}
finally {
yield put(loadingAction(false, identifier));
}
});
}
/**
* To log (Result=OK) this action, including action name and parameters (masked)
*/
export function Log() {
return (target) => {
const descriptor = target.descriptor;
const fn = descriptor.value;
descriptor.value = function* (...args) {
if (app.loggerConfig) {
// Do not use fn directly, it is a different object
const params = stringifyWithMask(app.loggerConfig.maskedKeywords || [], "***", ...args);
const logTypeName = descriptor.value.actionName;
const context = params ? { params } : {};
const onLogEnd = app.logger.info(logTypeName, context);
try {
yield* fn.bind(this)(...args);
}
finally {
onLogEnd();
}
}
else {
yield* fn.bind(this)(...args);
}
};
return target;
};
}
/**
* Required decorator when using lifecycle actions, including onRender/onDestroy/...
*/
export function Lifecycle() {
return (target) => {
const descriptor = target.descriptor;
descriptor.value.isLifecycle = true;
return target;
};
}
/**
* Used for onTick action, to specify to tick interval in second
*/
export function Interval(second) {
return (target) => {
const descriptor = target.descriptor;
descriptor.value.tickInterval = second;
return target;
};
}
/**
* If specified, the Saga action cannot be entered by other threads during execution
* Useful for error handler action
*/
export function Mutex() {
let isLocked = false;
return createActionHandlerDecorator(function* (handler) {
if (!isLocked) {
try {
isLocked = true;
yield* handler();
}
finally {
isLocked = false;
}
}
});
}
/**
* For Regular function ONLY
*
* Throttle the execution of a regular function
*/
export function Throttle(millisecond) {
let hasCalled = false;
return createRegularDecorator(handler => {
if (!hasCalled) {
handler();
hasCalled = true;
setTimeout(() => {
hasCalled = false;
}, millisecond);
}
});
}
/**
* For Regular function ONLY
*
* Memoize the last computed result, and return the same value if given the same input
* Input equality is based on JSON.stringify by default
* Only used for pure functions
*/
const defaultMemoKeyGenerator = (args) => JSON.stringify(args);
export function Memo(memoKeyGenerator = defaultMemoKeyGenerator) {
return (target) => {
const descriptor = target.descriptor;
const fn = descriptor.value;
const cache = {};
descriptor.value = (...args) => {
const paramKey = memoKeyGenerator(args);
if (!cache[paramKey]) {
cache[paramKey] = fn(...args);
}
return cache[paramKey];
};
return target;
};
}
//# sourceMappingURL=decorator.js.map