ez-saga 18.0.5 → 18.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/redux/PromiseMiddleware.js +13 -13
- package/lib/redux/PromiseMiddleware.js.map +1 -1
- package/lib/redux/createApp.js +60 -70
- package/lib/redux/createApp.js.map +1 -1
- package/package.json +5 -21
- package/src/index.ts +1 -1
- package/src/redux/PromiseMiddleware.ts +17 -14
- package/src/redux/createApp.ts +86 -90
- package/src/redux/typeDeclare.ts +0 -5
- package/src/global-shim.d.ts +0 -10
- package/src/index.js +0 -4
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 判断是否为标准Action
|
|
3
|
+
*/
|
|
4
|
+
function isAction(action) {
|
|
5
|
+
return typeof action === 'object' && action !== null && 'type' in action;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* 创建中间层
|
|
3
9
|
* @param registedModel 已注册model
|
|
@@ -6,22 +12,18 @@ function createPromiseMiddleware(registedModel) {
|
|
|
6
12
|
function isEffect(type) {
|
|
7
13
|
if (!type || typeof type !== 'string')
|
|
8
14
|
return false;
|
|
15
|
+
// 性能优化:快速排除不包含 '/' 的普通 Action
|
|
16
|
+
if (type.indexOf('/') === -1)
|
|
17
|
+
return false;
|
|
9
18
|
const [modelName, effect] = type.split('/');
|
|
10
19
|
const model = registedModel[modelName];
|
|
11
|
-
if (model) {
|
|
12
|
-
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
20
|
+
if (model && model.effects && model.effects[effect]) {
|
|
21
|
+
return true;
|
|
15
22
|
}
|
|
16
23
|
return false;
|
|
17
24
|
}
|
|
18
25
|
return (api) => (next) => (action) => {
|
|
19
|
-
|
|
20
|
-
if (action?.type !== undefined) {
|
|
21
|
-
const { type } = action;
|
|
22
|
-
exeEffect = isEffect(type);
|
|
23
|
-
}
|
|
24
|
-
if (exeEffect) {
|
|
26
|
+
if (isAction(action) && isEffect(action.type)) {
|
|
25
27
|
return new Promise((resolve, reject) => {
|
|
26
28
|
next({
|
|
27
29
|
_dy_resolve: resolve,
|
|
@@ -30,9 +32,7 @@ function createPromiseMiddleware(registedModel) {
|
|
|
30
32
|
});
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
return next(action);
|
|
35
|
-
}
|
|
35
|
+
return next(action);
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
export default createPromiseMiddleware;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromiseMiddleware.js","sourceRoot":"","sources":["../../src/redux/PromiseMiddleware.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,SAAS,uBAAuB,CAAqB,aAA4B;IAC/E,SAAS,QAAQ,CAAC,IAAY;QAC5B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"PromiseMiddleware.js","sourceRoot":"","sources":["../../src/redux/PromiseMiddleware.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,SAAS,QAAQ,CAAC,MAAe;IAC/B,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,IAAI,MAAM,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAqB,aAA4B;IAC/E,SAAS,QAAQ,CAAC,IAAY;QAC5B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAEpD,8BAA8B;QAC9B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAE3C,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAA0B,EAAE,EAAE,CAAC,CAAC,IAA8B,EAAE,EAAE,CAAC,CAAC,MAAe,EAAE,EAAE;QAC7F,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,IAAI,CAAC;oBACH,WAAW,EAAE,OAAO;oBACpB,UAAU,EAAE,MAAM;oBAClB,GAAG,MAAM;iBACV,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC;AAED,eAAe,uBAAuB,CAAC"}
|
package/lib/redux/createApp.js
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createSlice, combineReducers } from '@reduxjs/toolkit';
|
|
1
|
+
import { configureStore, createSlice, combineReducers } from '@reduxjs/toolkit';
|
|
3
2
|
import createSagaMiddleware from 'redux-saga';
|
|
4
3
|
import { call, put, select, takeEvery, putResolve } from 'redux-saga/effects';
|
|
5
|
-
import win from 'global/window';
|
|
6
4
|
import saveState from './defaultReducer';
|
|
7
5
|
import createPromiseMiddleware from './PromiseMiddleware';
|
|
6
|
+
// 提取公共的 Effect 工具对象,避免在循环中重复创建
|
|
7
|
+
const opFun = { call, put, putResolve, select };
|
|
8
|
+
/**
|
|
9
|
+
* 统一处理 Effect 的 Generator 函数
|
|
10
|
+
* 提取到外部以减少闭包创建,提升性能
|
|
11
|
+
*/
|
|
12
|
+
function* handleEffect(modelName, effectFunc, tools, action) {
|
|
13
|
+
// 开始异步任务设置loading状态
|
|
14
|
+
yield putResolve({ type: `${modelName}/saveState`, payload: { loading: true } });
|
|
15
|
+
// 执行 Effect (支持 Generator 或 Promise)
|
|
16
|
+
const ret = yield call(effectFunc, action, tools);
|
|
17
|
+
// 结束异步任务关闭loading状态
|
|
18
|
+
yield putResolve({ type: `${modelName}/saveState`, payload: { loading: false } });
|
|
19
|
+
// 处理 PromiseMiddleware 的回调
|
|
20
|
+
if (action._dy_resolve) {
|
|
21
|
+
action._dy_resolve(ret);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
/**
|
|
9
25
|
* 获取注册model函数
|
|
10
|
-
* @param store redux store
|
|
11
|
-
* @param registedModel 已注册model, 对象, 属性为model名称, value为model
|
|
12
|
-
* @param allReducers 所有的reducers
|
|
13
|
-
* @param sagaMiddleware saga中间件
|
|
14
|
-
* @returns 返回function regist(model)
|
|
15
26
|
*/
|
|
16
27
|
function getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware) {
|
|
17
|
-
/** model函数注册函数
|
|
18
|
-
* @param model 模块, 其格式为
|
|
19
|
-
* {
|
|
20
|
-
* name: 'name',
|
|
21
|
-
* state: {},
|
|
22
|
-
* reducers: {},
|
|
23
|
-
* effects: {}
|
|
24
|
-
* }
|
|
25
|
-
*/
|
|
26
28
|
return function regist(reduxModel) {
|
|
27
29
|
const model = {
|
|
28
30
|
...reduxModel,
|
|
@@ -31,76 +33,64 @@ function getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware) {
|
|
|
31
33
|
if (registedModel[model.name]) {
|
|
32
34
|
return;
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
// 初始化模型属性
|
|
37
|
+
if (!model.state)
|
|
35
38
|
model.state = {};
|
|
36
|
-
}
|
|
37
39
|
model.initialState = model.state;
|
|
38
|
-
if (!model.reducers)
|
|
40
|
+
if (!model.reducers)
|
|
39
41
|
model.reducers = {};
|
|
40
|
-
|
|
41
|
-
if (!model.reducers.saveState)
|
|
42
|
+
// 注入默认的 saveState reducer
|
|
43
|
+
if (!model.reducers.saveState)
|
|
42
44
|
model.reducers.saveState = saveState;
|
|
43
|
-
|
|
44
|
-
if (!model.effects) {
|
|
45
|
+
if (!model.effects)
|
|
45
46
|
model.effects = {};
|
|
46
|
-
|
|
47
|
-
const modelSlice = createSlice(
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
// 使用 Redux Toolkit 创建 Slice
|
|
48
|
+
const modelSlice = createSlice({
|
|
49
|
+
name: model.name,
|
|
50
|
+
initialState: model.initialState,
|
|
51
|
+
reducers: model.reducers
|
|
52
|
+
});
|
|
53
|
+
// 注册 Reducer
|
|
54
|
+
allReducers[model.name] = modelSlice.reducer;
|
|
50
55
|
registedModel[model.name] = model;
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
// 动态更新 Store 的 Reducers
|
|
57
|
+
const newReducer = combineReducers(allReducers);
|
|
53
58
|
store.replaceReducer(newReducer);
|
|
54
|
-
|
|
55
|
-
for (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function*
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
yield putResolve({ type: `${model.name}/saveState`, payload: { loading: false } });
|
|
64
|
-
if (action._dy_resolve) {
|
|
65
|
-
action._dy_resolve(ret);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function* runEffect() {
|
|
69
|
-
//yield takeLatest(type, loading, { call, put, putResolve, select });
|
|
70
|
-
yield takeEvery(type, loading, { call, put, putResolve, select });
|
|
71
|
-
}
|
|
72
|
-
sagaMiddleware.run(runEffect);
|
|
59
|
+
// 注册 Effects
|
|
60
|
+
for (const effectKey in model.effects) {
|
|
61
|
+
const type = `${model.name}/${effectKey}`;
|
|
62
|
+
const effectFunc = model.effects[effectKey];
|
|
63
|
+
sagaMiddleware.run(function* () {
|
|
64
|
+
// 使用 takeEvery 的参数传递功能,将上下文传入 handleEffect
|
|
65
|
+
// handleEffect(modelName, effectFunc, tools, action)
|
|
66
|
+
yield takeEvery(type, handleEffect, model.name, effectFunc, opFun);
|
|
67
|
+
});
|
|
73
68
|
}
|
|
74
69
|
};
|
|
75
70
|
}
|
|
76
71
|
/** 创建store */
|
|
77
72
|
export default function create() {
|
|
78
|
-
//已经注册的reducer, key是名字, value是reducer
|
|
79
73
|
const allReducers = {};
|
|
80
|
-
//已注册model
|
|
81
74
|
const registedModel = {};
|
|
82
75
|
const sagaMiddleware = createSagaMiddleware();
|
|
83
76
|
const promiseMiddleware = createPromiseMiddleware(registedModel);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
77
|
+
// 使用 configureStore 替代 createStore
|
|
78
|
+
// 自动集成 Redux DevTools,自动组合中间件
|
|
79
|
+
const store = configureStore({
|
|
80
|
+
reducer: saveState, // 初始 Reducer
|
|
81
|
+
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
|
82
|
+
thunk: false, // 禁用默认的 thunk,因为我们使用 saga
|
|
83
|
+
serializableCheck: false, // 禁用序列化检查,因为 action 中可能包含回调函数 (_dy_resolve)
|
|
84
|
+
immutableCheck: false // 禁用不可变检查,提升开发环境性能
|
|
85
|
+
}).concat(promiseMiddleware, sagaMiddleware),
|
|
86
|
+
devTools: process.env.NODE_ENV !== 'production',
|
|
87
|
+
preloadedState: {}
|
|
88
|
+
});
|
|
95
89
|
const regist = getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
sagaMiddleware: sagaMiddleware,
|
|
101
|
-
/** model注册函数 */
|
|
102
|
-
regist: regist
|
|
90
|
+
return {
|
|
91
|
+
store,
|
|
92
|
+
sagaMiddleware,
|
|
93
|
+
regist
|
|
103
94
|
};
|
|
104
|
-
return app;
|
|
105
95
|
}
|
|
106
96
|
//# sourceMappingURL=createApp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createApp.js","sourceRoot":"","sources":["../../src/redux/createApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"createApp.js","sourceRoot":"","sources":["../../src/redux/createApp.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ez-saga",
|
|
3
|
-
"version": "18.0.
|
|
3
|
+
"version": "18.0.6",
|
|
4
4
|
"description": "The ez-saga project is a project that imitates dva-js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -31,32 +31,17 @@
|
|
|
31
31
|
"@reduxjs/toolkit": "^2.11.2",
|
|
32
32
|
"redux": "^5.0.1",
|
|
33
33
|
"redux-saga": "^1.4.2",
|
|
34
|
-
"
|
|
34
|
+
"tslib": "^2.8.1"
|
|
35
35
|
},
|
|
36
|
-
"peerDependencies": {},
|
|
37
36
|
"devDependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"@babel/eslint-parser": "^7.23.3",
|
|
40
|
-
"@babel/plugin-proposal-decorators": "^7.23.7",
|
|
41
|
-
"@babel/plugin-syntax-flow": "^7.23.3",
|
|
42
|
-
"@babel/plugin-transform-runtime": "^7.23.7",
|
|
43
|
-
"@babel/preset-env": "^7.23.8",
|
|
44
|
-
"@babel/preset-flow": "^7.23.3",
|
|
45
|
-
"@babel/preset-typescript": "^7.23.3",
|
|
46
|
-
"@babel/runtime-corejs3": "^7.23.8",
|
|
47
|
-
"@babel/plugin-transform-class-properties": "^7.23.3",
|
|
48
|
-
"@babel/plugin-transform-private-methods": "^7.23.3",
|
|
49
|
-
"@babel/plugin-transform-private-property-in-object": "^7.23.4",
|
|
50
|
-
"cross-env": "^7.0.3",
|
|
51
|
-
"eslint": "^8.56.0",
|
|
52
|
-
"eslint-plugin-flowtype": "^8.0.3",
|
|
53
|
-
"eslint-plugin-import": "^2.29.1",
|
|
37
|
+
"@types/node": "^25.0.3",
|
|
54
38
|
"eslint-plugin-node": "^11.1.0",
|
|
55
39
|
"eslint-plugin-standard": "^4.1.0",
|
|
40
|
+
"rimraf": "^6.1.2",
|
|
56
41
|
"typescript": "^5.3.3"
|
|
57
42
|
},
|
|
58
43
|
"engines": {
|
|
59
|
-
"node": ">=
|
|
44
|
+
"node": ">= 18.0.0",
|
|
60
45
|
"npm": ">= 6.0.0"
|
|
61
46
|
},
|
|
62
47
|
"browserslist": [
|
|
@@ -68,7 +53,6 @@
|
|
|
68
53
|
"files": [
|
|
69
54
|
"lib",
|
|
70
55
|
"src",
|
|
71
|
-
"index.js",
|
|
72
56
|
"tsconfig.json",
|
|
73
57
|
"typing.d.ts"
|
|
74
58
|
]
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import { Dispatch, Middleware, MiddlewareAPI, Action } from 'redux';
|
|
1
|
+
import { Dispatch, Middleware, MiddlewareAPI, Action, UnknownAction } from 'redux';
|
|
2
2
|
import { RegistedModel } from './typeDeclare';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 判断是否为标准Action
|
|
6
|
+
*/
|
|
7
|
+
function isAction(action: unknown): action is Action<string> {
|
|
8
|
+
return typeof action === 'object' && action !== null && 'type' in action;
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
/**
|
|
5
12
|
* 创建中间层
|
|
6
13
|
* @param registedModel 已注册model
|
|
@@ -8,33 +15,29 @@ import { RegistedModel } from './typeDeclare';
|
|
|
8
15
|
function createPromiseMiddleware<D extends Dispatch>(registedModel: RegistedModel): Middleware<any, any, any> {
|
|
9
16
|
function isEffect(type: string) {
|
|
10
17
|
if (!type || typeof type !== 'string') return false;
|
|
18
|
+
|
|
19
|
+
// 性能优化:快速排除不包含 '/' 的普通 Action
|
|
20
|
+
if (type.indexOf('/') === -1) return false;
|
|
21
|
+
|
|
11
22
|
const [modelName, effect] = type.split('/');
|
|
12
23
|
const model = registedModel[modelName];
|
|
13
|
-
if (model) {
|
|
14
|
-
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
24
|
+
if (model && model.effects && model.effects[effect]) {
|
|
25
|
+
return true;
|
|
17
26
|
}
|
|
18
27
|
return false;
|
|
19
28
|
}
|
|
20
29
|
|
|
21
30
|
return (api: MiddlewareAPI<D, any>) => (next: (action: unknown) => any) => (action: unknown) => {
|
|
22
|
-
|
|
23
|
-
if ((action as Action)?.type !== undefined) {
|
|
24
|
-
const { type } = action as Action;
|
|
25
|
-
exeEffect = isEffect(type);
|
|
26
|
-
}
|
|
27
|
-
if (exeEffect) {
|
|
31
|
+
if (isAction(action) && isEffect(action.type)) {
|
|
28
32
|
return new Promise((resolve, reject) => {
|
|
29
33
|
next({
|
|
30
34
|
_dy_resolve: resolve,
|
|
31
35
|
_dy_reject: reject,
|
|
32
|
-
...action
|
|
36
|
+
...action,
|
|
33
37
|
});
|
|
34
38
|
});
|
|
35
|
-
} else {
|
|
36
|
-
return next(action);
|
|
37
39
|
}
|
|
40
|
+
return next(action);
|
|
38
41
|
};
|
|
39
42
|
}
|
|
40
43
|
|
package/src/redux/createApp.ts
CHANGED
|
@@ -1,126 +1,122 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createSlice, combineReducers } from '@reduxjs/toolkit';
|
|
1
|
+
import { configureStore, createSlice, combineReducers } from '@reduxjs/toolkit';
|
|
3
2
|
import createSagaMiddleware, { SagaMiddleware } from 'redux-saga';
|
|
4
3
|
import { call, put, select, takeEvery, putResolve } from 'redux-saga/effects';
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import { ReduxModel, ReduxApp, RegistedModel, ReduxSagaModel, EffectTool, PayloadAction } from './typeDeclare';
|
|
4
|
+
import { Reducer, Action, Store } from 'redux';
|
|
5
|
+
import { ReduxModel, ReduxApp, RegistedModel, ReduxSagaModel, EffectTool, PayloadAction, Effect } from './typeDeclare';
|
|
8
6
|
import saveState from './defaultReducer';
|
|
9
7
|
import createPromiseMiddleware from './PromiseMiddleware';
|
|
10
8
|
|
|
9
|
+
// 提取公共的 Effect 工具对象,避免在循环中重复创建
|
|
10
|
+
const opFun: EffectTool = { call, put, putResolve, select };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 统一处理 Effect 的 Generator 函数
|
|
14
|
+
* 提取到外部以减少闭包创建,提升性能
|
|
15
|
+
*/
|
|
16
|
+
function* handleEffect(
|
|
17
|
+
modelName: string,
|
|
18
|
+
effectFunc: Effect,
|
|
19
|
+
tools: EffectTool,
|
|
20
|
+
action: PayloadAction
|
|
21
|
+
) {
|
|
22
|
+
// 开始异步任务设置loading状态
|
|
23
|
+
yield putResolve({ type: `${modelName}/saveState`, payload: { loading: true } });
|
|
24
|
+
|
|
25
|
+
// 执行 Effect (支持 Generator 或 Promise)
|
|
26
|
+
const ret: any = yield call(effectFunc, action, tools);
|
|
27
|
+
|
|
28
|
+
// 结束异步任务关闭loading状态
|
|
29
|
+
yield putResolve({ type: `${modelName}/saveState`, payload: { loading: false } });
|
|
30
|
+
|
|
31
|
+
// 处理 PromiseMiddleware 的回调
|
|
32
|
+
if (action._dy_resolve) {
|
|
33
|
+
action._dy_resolve(ret);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
11
37
|
/**
|
|
12
38
|
* 获取注册model函数
|
|
13
|
-
* @param store redux store
|
|
14
|
-
* @param registedModel 已注册model, 对象, 属性为model名称, value为model
|
|
15
|
-
* @param allReducers 所有的reducers
|
|
16
|
-
* @param sagaMiddleware saga中间件
|
|
17
|
-
* @returns 返回function regist(model)
|
|
18
39
|
*/
|
|
19
|
-
function getRegistModelFunc(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* name: 'name',
|
|
26
|
-
* state: {},
|
|
27
|
-
* reducers: {},
|
|
28
|
-
* effects: {}
|
|
29
|
-
* }
|
|
30
|
-
*/
|
|
40
|
+
function getRegistModelFunc(
|
|
41
|
+
store: Store<any, Action<string>>,
|
|
42
|
+
registedModel: RegistedModel,
|
|
43
|
+
allReducers: { [x: string]: Reducer<any, any>; },
|
|
44
|
+
sagaMiddleware: SagaMiddleware<object>
|
|
45
|
+
): (model: ReduxModel) => void {
|
|
31
46
|
return function regist(reduxModel: ReduxModel): void {
|
|
32
47
|
const model = {
|
|
33
48
|
...reduxModel,
|
|
34
49
|
initialState: {}
|
|
35
50
|
} as ReduxSagaModel;
|
|
51
|
+
|
|
36
52
|
if (registedModel[model.name]) {
|
|
37
53
|
return;
|
|
38
54
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
55
|
+
|
|
56
|
+
// 初始化模型属性
|
|
57
|
+
if (!model.state) model.state = {};
|
|
42
58
|
model.initialState = model.state;
|
|
43
|
-
if (!model.reducers) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!model.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
model.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
if (!model.reducers) model.reducers = {};
|
|
60
|
+
// 注入默认的 saveState reducer
|
|
61
|
+
if (!model.reducers.saveState) model.reducers.saveState = saveState;
|
|
62
|
+
if (!model.effects) model.effects = {};
|
|
63
|
+
|
|
64
|
+
// 使用 Redux Toolkit 创建 Slice
|
|
65
|
+
const modelSlice = createSlice({
|
|
66
|
+
name: model.name,
|
|
67
|
+
initialState: model.initialState,
|
|
68
|
+
reducers: model.reducers as any
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 注册 Reducer
|
|
72
|
+
allReducers[model.name] = modelSlice.reducer;
|
|
55
73
|
registedModel[model.name] = model;
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
|
|
75
|
+
// 动态更新 Store 的 Reducers
|
|
76
|
+
const newReducer = combineReducers(allReducers);
|
|
58
77
|
store.replaceReducer(newReducer);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
yield
|
|
69
|
-
|
|
70
|
-
action._dy_resolve(ret);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function* runEffect() {
|
|
75
|
-
//yield takeLatest(type, loading, { call, put, putResolve, select });
|
|
76
|
-
yield takeEvery(type, loading, { call, put, putResolve, select });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
sagaMiddleware.run(runEffect);
|
|
78
|
+
|
|
79
|
+
// 注册 Effects
|
|
80
|
+
for (const effectKey in model.effects) {
|
|
81
|
+
const type = `${model.name}/${effectKey}`;
|
|
82
|
+
const effectFunc = model.effects[effectKey];
|
|
83
|
+
|
|
84
|
+
sagaMiddleware.run(function* () {
|
|
85
|
+
// 使用 takeEvery 的参数传递功能,将上下文传入 handleEffect
|
|
86
|
+
// handleEffect(modelName, effectFunc, tools, action)
|
|
87
|
+
yield takeEvery(type, handleEffect, model.name, effectFunc, opFun);
|
|
88
|
+
});
|
|
80
89
|
}
|
|
81
90
|
};
|
|
82
91
|
}
|
|
83
92
|
|
|
84
|
-
|
|
85
93
|
/** 创建store */
|
|
86
94
|
export default function create(): ReduxApp {
|
|
87
|
-
//已经注册的reducer, key是名字, value是reducer
|
|
88
95
|
const allReducers = {};
|
|
89
|
-
//已注册model
|
|
90
96
|
const registedModel: RegistedModel = {};
|
|
91
97
|
|
|
92
98
|
const sagaMiddleware = createSagaMiddleware();
|
|
93
|
-
|
|
94
99
|
const promiseMiddleware = createPromiseMiddleware(registedModel);
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const store = createStore(
|
|
110
|
-
saveState,
|
|
111
|
-
{},
|
|
112
|
-
composeEnhancers(...enhancers)
|
|
113
|
-
);
|
|
101
|
+
// 使用 configureStore 替代 createStore
|
|
102
|
+
// 自动集成 Redux DevTools,自动组合中间件
|
|
103
|
+
const store = configureStore({
|
|
104
|
+
reducer: saveState, // 初始 Reducer
|
|
105
|
+
middleware: (getDefaultMiddleware) =>
|
|
106
|
+
getDefaultMiddleware({
|
|
107
|
+
thunk: false, // 禁用默认的 thunk,因为我们使用 saga
|
|
108
|
+
serializableCheck: false, // 禁用序列化检查,因为 action 中可能包含回调函数 (_dy_resolve)
|
|
109
|
+
immutableCheck: false // 禁用不可变检查,提升开发环境性能
|
|
110
|
+
}).concat(promiseMiddleware, sagaMiddleware),
|
|
111
|
+
devTools: process.env.NODE_ENV !== 'production',
|
|
112
|
+
preloadedState: {}
|
|
113
|
+
});
|
|
114
114
|
|
|
115
115
|
const regist = getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware);
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
sagaMiddleware: sagaMiddleware,
|
|
122
|
-
/** model注册函数 */
|
|
123
|
-
regist: regist
|
|
117
|
+
return {
|
|
118
|
+
store,
|
|
119
|
+
sagaMiddleware,
|
|
120
|
+
regist
|
|
124
121
|
};
|
|
125
|
-
return app;
|
|
126
122
|
}
|
package/src/redux/typeDeclare.ts
CHANGED
|
@@ -20,11 +20,6 @@ declare module 'redux' {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// /** 定义AsyncDispatch, 使其兼容redux promiseMiddleware中间件修改返回结果的情况 */
|
|
24
|
-
// export interface AsyncDispatch {
|
|
25
|
-
// <R = any>(action: PayloadAction, ...extraArgs: any[]): Promise<R>;
|
|
26
|
-
// }
|
|
27
|
-
|
|
28
23
|
/** 工具 */
|
|
29
24
|
export interface EffectTool {
|
|
30
25
|
/** 调用异步函数, 并获得该异步函数的结果 */
|
package/src/global-shim.d.ts
DELETED
package/src/index.js
DELETED