分享一篇自己阅读saga-duck源码的笔记 希望对后续研究saga-duck的同学有所帮助 欢迎指正


DuckCmpProps 全名:DuckComponentProps 是一个interface接口 为后续React组件提供类型支持 需要传入泛型
其中有duck store dispatch三个属性 duck:就是我们自己定义传入的duck store:状态数据的中心,单一数据源 dispatch:触发一个action 也就是creators
selectors:将duck上的state上的属性出来 获取selectors 就是 将 selectors变成一个方法
源码实现最后可以简化为

duck.selectors.[key] = function(globalState) {
  rawSelectors[key](selector(globalState))
}

为什么需要这一步 应该是为了类型支持 那我们再来看一看rawSelectors是怎么实现的 rawSelectors是自己定义在Duck里面的 需要传入State 最后返回State[key] 相当于数据库中的select查询 这也就是这个名称的由来吧

rawSelectors 里面有用到一个type State = MyDuck[‘State’] 这样就把类上定义的 State 抽成了一个类型 方便后续TS类型提示 我们来看一下State是怎么定义的

get State(): ReturnType<this["reducer"]> {
  return null;
}

State是一个存取访问器 我们来看看ReturnType是个什么东西 TS 中 infer表示待推断的类型 ReturnType 就是利用infer 来将 reducer 的返回值 形成一个类型的

再来看下selector的实现 它是在constructor 作为options的一个属性在构造函数参数传入的 TS类型为 DuckOptions 里面有三个属性 namespace selector route 第一层没什么特别的 我们来看看组合duck的代码

new Duck(this.getSubDuckOptions(route))

protected getSubDuckOptions(route: string): DuckOptions {
  const { namespace, route: parentRoute } = this.options;
  const parentSelector = this.selector;
  return {
    namespace,
    route: parentRoute ? `${parentRoute}/${route}` : route,
    selector: state => parentSelector(state)[route]
  };
}

可以看到 在makeDucks方法中 遍历了所有的子duck 其中传入构造函数的参数options options会根据当前的route和遍历的duck定义的key值 形成新的route和selector

为什么只能selectors.counter获取自身duck内的值 因为new Duck(options) 中的options定义了route当前路由、selector只获取当前route中的state

之前一直有个疑问 子duck怎么获取父duck上的state呢? 其实很简单通过rawSelectors 比如: rawSelectors.counter 就可以获取 原因就是rawSelectors 没有经过duck.selector的包装 所以取了全局的state

这样 所有的流程就串起来了 saga-duck其实就做了一个很关键的事,让Redux更方便的使用TS类型系统

总结:函数式 + 面向对象 + TS = 真香