Skip to content

Commit

Permalink
add plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Doong committed Jul 18, 2024
1 parent ed88fce commit 7375cc8
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 51 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redext",
"version": "0.0.14",
"version": "0.0.16-7",
"description": "A simple global store based on React Context and Hooks",
"main": "./dist/index.js",
"module": "./dist/esm/index.mjs",
Expand Down
20 changes: 19 additions & 1 deletion src/Provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Provider = (props) => {
return stateRef.current;
};

const { effects, dispatch: dispatcher } = store.getEffect(dispatch, state);
const { effects, dispatch: dispatcher, models, on } = store.getEffect(dispatch, state);

const subscribe = (listener) => {
listeners.add(listener);
Expand All @@ -37,6 +37,24 @@ const Provider = (props) => {
getState,
state: getState(),
dispatch: (arg) => {
on('onModel', (onModel) => {
const type = arg?.type;
const types = type.split('/');
const modelName = types[0];
const actionName = types[1];
const model = models[modelName];

onModel({
model: {
...model,
name: modelName
},
modelName,
actionName,
dispatch: dispatcher
})
});

dispatcher(arg);

listeners.forEach((l) => l());
Expand Down
146 changes: 99 additions & 47 deletions src/createStore.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,138 @@
function merge(original, extra) {
return extra ? { ...extra, ...original } : original
}

export default function createStore(config = {}) {
const { plugins = [] } = config;

plugins.forEach((plugin) => {
if (plugin.config) {
config.models = merge(config.models, plugin.config.models);
}
});

const on = (eventName, callback) => {
plugins.forEach((plugin) => {
if (plugin[eventName]) {
callback(plugin[eventName])
}
})
}

const { models = {} } = config;

const getState = (initialState = {}) => {
const newInitialState = {};

Object.keys(models).forEach((modelFilename) => {
const dataModel = models[modelFilename] || {};
const modelName = dataModel.name || modelFilename;
newInitialState[modelName] = Object.assign({}, dataModel.state, initialState[modelName])
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) => {
const dataModel = models[modelFilename] || {};
const { reducers = {}, name: modelName = modelFilename } = dataModel;
const model = models[modelFilename] || {};

const { reducers = {}, name: modelName = modelFilename } = model;

let reducerState = state[modelName];

const actionType = action.type.replace(`${modelName}/`, '');

if (actionType in reducers) {
reducerState = reducers[actionType](reducerState, action.payload);
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 dataModel = models[modelFilename] || {};

const { reducers = {}, effects: effectsToConfig = {}, name: modelName = modelFilename } = dataModel;

modelDispatcher.state = state[modelFilename];

Object.keys(reducers).forEach((reducerName) => {
const type = `${modelName}/${reducerName}`;

modelDispatcher[reducerName] = (payload) => dispatch({ type, payload });
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) => {
// onModelListener({ actionName });
dispatch({ type, payload, params });
};
});

let effects;
dispatch[modelFilename] = modelDispatcher;
if (typeof effectsToConfig === 'function') {
effects = effectsToConfig(dispatch)

dispatch[modelName] = modelDispatcher;

if (typeof effectsFromConfig === 'function') {
effects = effectsFromConfig(dispatch)
} else {
effects = effectsToConfig;
effects = effectsFromConfig;
}

const effectObj = {};

Object.keys(effects).forEach((effectName) => {
modelDispatcher[effectName] = effects[effectName].bind(modelDispatcher);

effectObj[effectName] = effects[effectName].bind(modelDispatcher)
const effectFunc = (...args) => {
onModelListener({
actionName: effectName
});

const callback = effects[effectName].bind(modelDispatcher);

return callback(...args)
}

modelDispatcher[effectName] = effectFunc;
effectObj[effectName] = effectFunc;
});

newEffects[modelName] = effectObj;
});

return {
effects: newEffects,
dispatch
models,
dispatch,
on
};
};

return {
getState,
getReducer,
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useContextSelector.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useSyncExternalStore } from 'react';
import { useContext, useSyncExternalStore } from 'react';
import Context from '../Context';
import useDeepMemo from './useDeepMemo';

Expand Down
1 change: 0 additions & 1 deletion src/hooks/useSelector.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React, { useContext } from 'react';
import useContextSelector from './useContextSelector';

const useSelector = (mapStateToProps) => {
Expand Down
45 changes: 45 additions & 0 deletions src/plugins/loading/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const validateConfig = (config) => {
}

export default (config = {}) => {
const modelName = config.name || 'loading';

const loading = {
name: modelName,
state: {
global: 0,
models: {},
effects: {}
},
effects: () => {
return {
show: () => {

},
hide: () => {

}
}
},
reducers: {
updateState: (state, payload) => {
if (typeof payload === 'function') {
payload = payload(state);
}

return {
...state,
...payload
};
}
}
}

return {
config: {
models: {
loading
}
}
}
}

0 comments on commit 7375cc8

Please sign in to comment.