ez-saga 18.0.4 → 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/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { PayloadAction, EffectTool, Effect, ModelReducer, ModelEffect, ReduxModel, ReduxApp } from './redux/typeDeclare';
2
+ export { Dispatch, Action } from 'redux';
3
+ import createApp from './redux/createApp';
4
+ declare const _default: {
5
+ createApp: typeof createApp;
6
+ };
7
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import createApp from './redux/createApp';
2
+ export default {
3
+ createApp: createApp
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,eAAe;IACb,SAAS,EAAE,SAAS;CACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { Dispatch, Middleware } from 'redux';
2
+ import { RegistedModel } from './typeDeclare';
3
+ /**
4
+ * 创建中间层
5
+ * @param registedModel 已注册model
6
+ */
7
+ declare function createPromiseMiddleware<D extends Dispatch>(registedModel: RegistedModel): Middleware<any, any, any>;
8
+ export default createPromiseMiddleware;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 判断是否为标准Action
3
+ */
4
+ function isAction(action) {
5
+ return typeof action === 'object' && action !== null && 'type' in action;
6
+ }
7
+ /**
8
+ * 创建中间层
9
+ * @param registedModel 已注册model
10
+ */
11
+ function createPromiseMiddleware(registedModel) {
12
+ function isEffect(type) {
13
+ if (!type || typeof type !== 'string')
14
+ return false;
15
+ // 性能优化:快速排除不包含 '/' 的普通 Action
16
+ if (type.indexOf('/') === -1)
17
+ return false;
18
+ const [modelName, effect] = type.split('/');
19
+ const model = registedModel[modelName];
20
+ if (model && model.effects && model.effects[effect]) {
21
+ return true;
22
+ }
23
+ return false;
24
+ }
25
+ return (api) => (next) => (action) => {
26
+ if (isAction(action) && isEffect(action.type)) {
27
+ return new Promise((resolve, reject) => {
28
+ next({
29
+ _dy_resolve: resolve,
30
+ _dy_reject: reject,
31
+ ...action,
32
+ });
33
+ });
34
+ }
35
+ return next(action);
36
+ };
37
+ }
38
+ export default createPromiseMiddleware;
39
+ //# sourceMappingURL=PromiseMiddleware.js.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,3 @@
1
+ import { ReduxApp } from './typeDeclare';
2
+ /** 创建store */
3
+ export default function create(): ReduxApp;
@@ -0,0 +1,96 @@
1
+ import { configureStore, createSlice, combineReducers } from '@reduxjs/toolkit';
2
+ import createSagaMiddleware from 'redux-saga';
3
+ import { call, put, select, takeEvery, putResolve } from 'redux-saga/effects';
4
+ import saveState from './defaultReducer';
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
+ }
24
+ /**
25
+ * 获取注册model函数
26
+ */
27
+ function getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware) {
28
+ return function regist(reduxModel) {
29
+ const model = {
30
+ ...reduxModel,
31
+ initialState: {}
32
+ };
33
+ if (registedModel[model.name]) {
34
+ return;
35
+ }
36
+ // 初始化模型属性
37
+ if (!model.state)
38
+ model.state = {};
39
+ model.initialState = model.state;
40
+ if (!model.reducers)
41
+ model.reducers = {};
42
+ // 注入默认的 saveState reducer
43
+ if (!model.reducers.saveState)
44
+ model.reducers.saveState = saveState;
45
+ if (!model.effects)
46
+ model.effects = {};
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;
55
+ registedModel[model.name] = model;
56
+ // 动态更新 Store 的 Reducers
57
+ const newReducer = combineReducers(allReducers);
58
+ store.replaceReducer(newReducer);
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
+ });
68
+ }
69
+ };
70
+ }
71
+ /** 创建store */
72
+ export default function create() {
73
+ const allReducers = {};
74
+ const registedModel = {};
75
+ const sagaMiddleware = createSagaMiddleware();
76
+ const promiseMiddleware = createPromiseMiddleware(registedModel);
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
+ });
89
+ const regist = getRegistModelFunc(store, registedModel, allReducers, sagaMiddleware);
90
+ return {
91
+ store,
92
+ sagaMiddleware,
93
+ regist
94
+ };
95
+ }
96
+ //# sourceMappingURL=createApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createApp.js","sourceRoot":"","sources":["../../src/redux/createApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** 默认reducer */
2
+ import { Reducer } from 'redux';
3
+ import { PayloadAction } from './typeDeclare';
4
+ declare const saveState: Reducer<any, PayloadAction>;
5
+ export default saveState;
@@ -0,0 +1,12 @@
1
+ const saveState = (state, action) => {
2
+ if (!action.payload) {
3
+ return state;
4
+ }
5
+ let newStat = {
6
+ ...state,
7
+ ...action.payload
8
+ };
9
+ return newStat;
10
+ };
11
+ export default saveState;
12
+ //# sourceMappingURL=defaultReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultReducer.js","sourceRoot":"","sources":["../../src/redux/defaultReducer.ts"],"names":[],"mappings":"AAIA,MAAM,SAAS,GAAgC,CAAC,KAAU,EAAE,MAAqB,EAAE,EAAE;IACnF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,GAAG;QACZ,GAAG,KAAK;QACR,GAAG,MAAM,CAAC,OAAO;KAClB,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -0,0 +1,64 @@
1
+ /** 类型申明 */
2
+ import { Action as ReduxAction, Store, Reducer, UnknownAction } from 'redux';
3
+ import { Action, SagaMiddleware } from 'redux-saga';
4
+ import { PutEffect, SelectEffect } from 'redux-saga/effects';
5
+ /** payload action类型 */
6
+ export interface PayloadAction extends UnknownAction, ReduxAction<string> {
7
+ /** 类型 */
8
+ type: string;
9
+ /** 载体 */
10
+ payload?: any;
11
+ [extraProps: string]: any;
12
+ }
13
+ declare module 'redux' {
14
+ interface Dispatch {
15
+ <R = any>(action: PayloadAction, ...extraArgs: any[]): Promise<R>;
16
+ }
17
+ }
18
+ /** 工具 */
19
+ export interface EffectTool {
20
+ /** 调用异步函数, 并获得该异步函数的结果 */
21
+ call: (...args: any[]) => any;
22
+ /** 分发异步action */
23
+ put: <A extends Action>(action: A) => PutEffect<A>;
24
+ /** 分发同步action */
25
+ putResolve: <A extends Action>(action: A) => PutEffect<A>;
26
+ /** 从store从获取状态 */
27
+ select: ((selectFunc: (state: any) => any) => SelectEffect) | (() => SelectEffect);
28
+ }
29
+ /** Effect函数类型 */
30
+ export interface Effect {
31
+ (action: PayloadAction, tool: EffectTool): Generator | Promise<any> | any;
32
+ }
33
+ /** ModelReducer定义 */
34
+ export interface ModelReducer {
35
+ [key: string]: Reducer<any, PayloadAction>;
36
+ }
37
+ /** ModelEffect定义 */
38
+ export interface ModelEffect {
39
+ [key: string]: Effect;
40
+ }
41
+ export interface ReduxModel {
42
+ name: string;
43
+ state?: any;
44
+ reducers?: ModelReducer;
45
+ effects?: ModelEffect;
46
+ }
47
+ export interface ReduxSagaModel extends ReduxModel {
48
+ initialState: any;
49
+ reducerPath: string;
50
+ reducers: ModelReducer;
51
+ }
52
+ export interface RegistedModel {
53
+ [key: string]: ReduxModel;
54
+ }
55
+ /** app */
56
+ export interface ReduxApp {
57
+ store: Store<any, ReduxAction>;
58
+ sagaMiddleware: SagaMiddleware<object>;
59
+ regist: (model: ReduxModel) => void;
60
+ }
61
+ export interface ReduxSagaModel extends ReduxModel {
62
+ initialState: any;
63
+ reducers: ModelReducer;
64
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=typeDeclare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeDeclare.js","sourceRoot":"","sources":["../../src/redux/typeDeclare.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "ez-saga",
3
- "version": "18.0.4",
3
+ "version": "18.0.6",
4
4
  "description": "The ez-saga project is a project that imitates dva-js",
5
- "main": "src/index.js",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
6
7
  "sideEffects": false,
7
8
  "repository": {
8
9
  "type": "git",
@@ -22,57 +23,25 @@
22
23
  ],
23
24
  "license": "MIT",
24
25
  "scripts": {
25
- "build:prod": "cross-env NODE_ENV=production APP_ENV=prod node build/build.js",
26
+ "build:prod": "rimraf lib && tsc",
27
+ "build:types": "tsc",
26
28
  "lint": "eslint --ext .js src"
27
29
  },
28
30
  "dependencies": {
29
- "@reduxjs/toolkit": "^2.1.0",
31
+ "@reduxjs/toolkit": "^2.11.2",
30
32
  "redux": "^5.0.1",
31
- "redux-saga": "^1.3.0",
32
- "global": "^4.4.0"
33
+ "redux-saga": "^1.4.2",
34
+ "tslib": "^2.8.1"
33
35
  },
34
- "peerDependencies": {},
35
36
  "devDependencies": {
36
- "@babel/core": "^7.23.7",
37
- "@babel/eslint-parser": "^7.23.3",
38
- "@babel/plugin-proposal-decorators": "^7.23.7",
39
- "@babel/plugin-syntax-flow": "^7.23.3",
40
- "@babel/plugin-transform-runtime": "^7.23.7",
41
- "@babel/preset-env": "^7.23.8",
42
- "@babel/preset-flow": "^7.23.3",
43
- "@babel/preset-typescript": "^7.23.3",
44
- "@babel/runtime-corejs3": "^7.23.8",
45
- "@babel/plugin-transform-class-properties": "^7.23.3",
46
- "@babel/plugin-transform-private-methods": "^7.23.3",
47
- "@babel/plugin-transform-private-property-in-object": "^7.23.4",
48
- "autoprefixer": "^10.4.17",
49
- "babel-loader": "^9.1.3",
50
- "babel-plugin-dynamic-import-webpack": "^1.1.0",
51
- "babel-plugin-import": "^1.13.8",
52
- "chalk": "^4.1.2",
53
- "copy-webpack-plugin": "^12.0.2",
54
- "core-js": "^3.35.1",
55
- "cross-env": "^7.0.3",
56
- "eslint": "^8.56.0",
57
- "eslint-plugin-flowtype": "^8.0.3",
58
- "eslint-plugin-import": "^2.29.1",
37
+ "@types/node": "^25.0.3",
59
38
  "eslint-plugin-node": "^11.1.0",
60
39
  "eslint-plugin-standard": "^4.1.0",
61
- "eslint-webpack-plugin": "^4.0.1",
62
- "rimraf": "^5.0.5",
63
- "semver": "^7.5.4",
64
- "shelljs": "^0.8.5",
65
- "terser-webpack-plugin": "^5.3.10",
66
- "webpack": "^5.89.0",
67
- "webpack-bundle-analyzer": "^4.10.1",
68
- "webpack-cli": "^5.1.4",
69
- "webpack-dev-server": "^4.15.1",
70
- "webpack-merge": "^5.10.0",
71
- "ts-loader": "^9.5.1",
40
+ "rimraf": "^6.1.2",
72
41
  "typescript": "^5.3.3"
73
42
  },
74
43
  "engines": {
75
- "node": ">= 14.0.0",
44
+ "node": ">= 18.0.0",
76
45
  "npm": ">= 6.0.0"
77
46
  },
78
47
  "browserslist": [
@@ -82,11 +51,9 @@
82
51
  "not op_mini all"
83
52
  ],
84
53
  "files": [
85
- "dist",
86
54
  "lib",
87
55
  "src",
88
- "index.js",
89
- "tysconfig.json",
56
+ "tsconfig.json",
90
57
  "typing.d.ts"
91
58
  ]
92
59
  }
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
+
1
2
  export { PayloadAction, EffectTool, Effect, ModelReducer, ModelEffect, ReduxModel, ReduxApp } from './redux/typeDeclare';
3
+ export { Dispatch, Action } from 'redux';
2
4
  import createApp from './redux/createApp';
3
5
  export default {
4
6
  createApp: createApp
@@ -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
- if (model.effects && model.effects[effect]) {
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
- let exeEffect = false;
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 as 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
 
@@ -1,126 +1,122 @@
1
- import { legacy_createStore as createStore, applyMiddleware, compose, Action as ReduxAction, Store } from 'redux';
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 win from 'global/window';
6
- import { Reducer, Action } from 'redux';
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(store: Store<any, ReduxAction>, registedModel: RegistedModel,
20
- allReducers: { [x: string]: Reducer<any, Action>; },
21
- sagaMiddleware: SagaMiddleware<object>): (model: ReduxModel) => void {
22
- /** model函数注册函数
23
- * @param model 模块, 其格式为
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
- if (!model.state) {
40
- model.state = {};
41
- }
55
+
56
+ // 初始化模型属性
57
+ if (!model.state) model.state = {};
42
58
  model.initialState = model.state;
43
- if (!model.reducers) {
44
- model.reducers = {};
45
- }
46
- if (!model.reducers.saveState) {
47
- model.reducers.saveState = saveState;
48
- }
49
- if (!model.effects) {
50
- model.effects = {};
51
- }
52
- const modelSlice = createSlice(model);
53
- const reducer = modelSlice.reducer;
54
- allReducers[model.name] = reducer;
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
- //获得一个新的reducer, 将所有的reducer整合成一个
57
- let newReducer = combineReducers(allReducers);
74
+
75
+ // 动态更新 Store 的 Reducers
76
+ const newReducer = combineReducers(allReducers);
58
77
  store.replaceReducer(newReducer);
59
- //注册effects
60
- for (let effect in model.effects) {
61
- let type: string = `${model.name}/${effect}`;
62
- let execFun = model.effects[effect];
63
- function* loading(opFun: EffectTool, action: PayloadAction) {
64
- // 开始异步任务设置loading状态
65
- yield putResolve({ type: `${model.name}/saveState`, payload: { loading: true } });
66
- let ret = yield call(execFun, action, opFun);
67
- // 结束异步任务关闭loading状态
68
- yield putResolve({ type: `${model.name}/saveState`, payload: { loading: false } });
69
- if (action._dy_resolve) {
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
- const middlewares = [
97
- promiseMiddleware,
98
- sagaMiddleware
99
- ];
100
-
101
- // eslint-disable-next-line no-undef
102
- const composeEnhancers = process.env.NODE_ENV !== 'production'
103
- && win.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
104
- win.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true, maxAge: 30 }) : compose;
105
-
106
- const enhancers = [applyMiddleware(...middlewares)];
107
-
108
- //redux store
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
- let app: ReduxApp = {
118
- /** redux store */
119
- store: store,
120
- /** saga中间件 */
121
- sagaMiddleware: sagaMiddleware,
122
- /** model注册函数 */
123
- regist: regist
117
+ return {
118
+ store,
119
+ sagaMiddleware,
120
+ regist
124
121
  };
125
- return app;
126
122
  }