了解redux-duck
最近参与维护一些项目,其中有用到saga-duck,一脸茫然,于是了解了下,有点收获,这里Mark。
关联技术点
saga-duck的学习,延伸出duck,extensible-duck,redux-saga,这些都有必要提下。
Duck
一种模式/观点
,当使用redux时,我们往往将{actionTypes,actions,reducers}
三种物理分离,实际上很多操作不存在不同业务场景的复用,将其放在一起组织似乎更合理。
这种思想实际上希望将redux这块的代码进行模块化管理,而非生硬的按照功能类别划分。
extensible-duck
duck模式的一种实现,并且支持redux-saga
redux-saga
redux-reducer本身只是纯函数,每次操作即一种状态转化为另一种状态,我们固定输入一定即固定了输出,所以reducer都是纯函数。而很多时候会有一些异步操作等,这些操作存在副作用,因此redux-thunk,redux-saga即为了解决这个环节的问题而存在。只是saga更为复杂&强大些。
saga-duck
saga-duck大部分是借鉴的extensible-duck,官方文档描述是extensible-duck没有考虑支持redux-saga,并且组合使用不太方便,因此才开发了这个工具库。不过extensible-duck已经支持了saga。
因此extensible-duck/saga-duck等选其一即可。
saga-duck实践
官方demo及我这里的demo已经可以说明白,这里不再反复说明。
我的理解即
- 单一业务下的数据流转包含副作用处理都可以在一个duck下进行组织处理
- 如果有类似的可以做继承/组合进行复用
遇到的坑
Class constructor Duck cannot be invoked without ’new'
如果打包遇到该错误即编译这块的事。saga-duck包JS为ES6,而如果我们项目本身编译后是ES5,因此运行中不会有new,而对于ES6 class不使用new运算符志直接使用则会报以上错误,解决办法可以将saga-duck包含在babel编译的范围内
{
test: /\.(js|jsx|mjs)$/,
include:
[
paths.appSrc,
/\/node_modules\/saga-duck/, // 关键部分
],
loader: require.resolve('babel-loader'),
options: {
configFile: './.babelrc.json',
cacheDirectory: true
}
}
saga-duck原理
duck本身只是提供了类的形式进行redux相关代码组织,整个封装即duck,然后当new一个duck时,会创建redux store。
const duckRuntime = new DuckRuntime(new MyDuck());
const ConnectedC = duckRuntime.connectRoot()(DuckTest);
const ConnectedComponent = () =>
<Provider store={duckRuntime.store}>
<ConnectedC />
</Provider>;
constructor(duck: TDuck, ...middlewares: any[]){
this.duck = duck;
let options: DuckRuntimeOptions
if(middlewares.length === 1 && typeof middlewares[0] === 'object'){
options = middlewares[0]
}else{
options = {
middlewares
}
}
this.middlewares = options.middlewares || [];
this.enhancers = options.enhancers || [];
this._initStore();
}
/**
* 创建redux store
*/
protected _initStore() {
const duck = this.duck;
const sagaMiddleware = (this.sagaMiddleware = createSagaMiddleware());
const enhancer = compose(
applyMiddleware(sagaMiddleware, ...this.middlewares),
...this.enhancers,
);
this.store = createReduxStore(<any>duck.reducer, <any>enhancer);
this.addSaga(duck.sagas);
}
写在最后
正如开始所说,duck是一种模式,理解这点就不难使用。