redext
Version:
A simple global store based on React Context and Hooks
96 lines (95 loc) • 3.22 kB
JavaScript
// src/createStore.ts
var merge = (original, extra) => {
return extra ? { ...extra, ...original } : original;
};
function createStore(config) {
const { plugins = [] } = config;
let models = config.models;
plugins.forEach((plugin) => {
if (plugin.config) {
models = merge(models, plugin.config.models);
}
});
const on = (eventName, callback) => {
plugins.forEach((plugin) => {
if (plugin[eventName]) {
callback(plugin[eventName]);
}
});
};
const getState = (initialState = {}) => {
const newInitialState = {};
Object.keys(models).forEach((modelFilename) => {
const model = models[modelFilename] || {};
const modelName = model.name || modelFilename;
newInitialState[modelName] = Object.assign({}, model.state, initialState[modelName]);
});
return newInitialState;
};
const getReducer = (state = {}, action = {}) => {
const newState = {};
Object.keys(models).forEach((modelFilename) => {
var _a, _b;
const model = models[modelFilename] || {};
const { reducers = {}, name: modelName = modelFilename } = model;
let reducerState = state[modelName];
const actionType = (_b = (_a = action.type) == null ? void 0 : _a.replace) == null ? void 0 : _b.call(_a, `${modelName}/`, "");
if (actionType && actionType in reducers) {
reducerState = reducers[actionType](reducerState, action.payload, action.params);
}
newState[modelName] = reducerState;
});
return newState;
};
const getEffect = (dispatch, state = {}) => {
const newEffects = {};
Object.keys(models).forEach((modelFilename) => {
const modelDispatcher = {};
const model = models[modelFilename] || {};
const { reducers = {}, effects: effectsFromConfig, name: modelName = modelFilename } = model;
modelDispatcher.state = state[modelName];
const onModelListener = ({ actionName }) => {
on("onModel", (onModel) => {
onModel({
model: { ...model, name: modelName },
modelName,
actionName,
dispatch
});
});
};
Object.keys(reducers).forEach((actionName) => {
const type = `${modelName}/${actionName}`;
modelDispatcher[actionName] = (payload, params) => {
dispatch({
type,
payload,
params
});
};
});
let effects;
dispatch[modelName] = modelDispatcher;
if (typeof effectsFromConfig === "function") {
effects = effectsFromConfig(dispatch);
} else {
effects = effectsFromConfig || {};
}
const effectObj = {};
Object.keys(effects).forEach((effectName) => {
const effectFunc = (...args) => {
onModelListener({ actionName: effectName });
return effects[effectName].apply(modelDispatcher, args);
};
modelDispatcher[effectName] = effectFunc;
effectObj[effectName] = effectFunc;
});
newEffects[modelName] = effectObj;
});
return { effects: newEffects, models, dispatch, on };
};
return { getState, getReducer, getEffect };
}
export {
createStore as default
};