core-native
Version:
A lightweight framework based on React Native + Redux + Redux Saga, in strict TypeScript.
86 lines (72 loc) • 2.35 kB
text/typescript
import {type Action as ReduxAction, combineReducers, type Reducer} from "redux";
// Redux State
interface LoadingState {
[loading: string]: number;
}
export interface State {
loading: LoadingState;
app: {
[key: string]: object;
};
}
// Redux Action
const SET_STATE_ACTION = "@@framework/setState";
export interface Action<P> extends ReduxAction<string> {
payload: P;
name?: typeof SET_STATE_ACTION;
}
// Redux Action: SetState (to update state.app)
interface SetStateActionPayload {
module: string;
state: any;
}
// state must be complete module state, not partial
export function setStateAction(module: string, state: object, type: string): Action<SetStateActionPayload> {
return {
type,
name: SET_STATE_ACTION,
payload: {module, state},
};
}
function setStateReducer(state: State["app"] = {}, action: Action<any>): State["app"] {
// Use action.name for set state action, make type specifiable to make tracking/tooling easier
if (action.name === SET_STATE_ACTION) {
const {module, state: moduleState} = action.payload as SetStateActionPayload;
return {...state, [module]: moduleState};
}
return state;
}
// Redux Action: Loading (to update state.loading)
interface LoadingActionPayload {
identifier: string;
show: boolean;
}
export const LOADING_ACTION = "@@framework/loading";
export function loadingAction(show: boolean, identifier: string = "global"): Action<LoadingActionPayload> {
return {
type: LOADING_ACTION,
payload: {identifier, show},
};
}
function loadingReducer(state: LoadingState = {}, action: Action<LoadingActionPayload>): LoadingState {
if (action.type === LOADING_ACTION) {
const payload = action.payload as LoadingActionPayload;
const count = state[payload.identifier] || 0;
return {
...state,
[payload.identifier]: count + (payload.show ? 1 : -1),
};
}
return state;
}
// Root Reducer
export function rootReducer(): Reducer<State> {
return combineReducers<State>({
loading: loadingReducer,
app: setStateReducer,
});
}
// Helper function, to determine if show loading
export function showLoading(state: State, identifier: string = "global") {
return state.loading[identifier] > 0;
}