You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
聊聊我对 dva 的看法,官方说了,基于 redux + redux-saga 的方案,只是在你写的时候,都写在一个 model 文件,然后它帮你做一些处理;其次它是一个框架,而不是一个库,是否意味着: 我在项目开始之前,我就需要确定项目的架构是不是用 dva,如果开发一半,我想换成 dva 这种状态管理的写法,而去引入 dva ,是否不合理?
再或者,我只是做一些 demo、写点小型的个人项目,但我又想像写 dva 的数据状态管理 model 那种方式,引入 dva 是不是反而变得笨重呢?
前言
大家应该知道,react 是单向数据流的形式,它不存在数据向上回溯的技能,你要么就是向下分发,要么就是自己内部管理。
react 中,有 props 和 state,当我想从父组件给子组件传递数据的时候,可通过 props 进行数据传递,如果我想在组件内部自行管理状态,那可以选择使用 state。
很快,我遇到了一个问题,那就是兄弟组件之间如何进行通信?答案就是在父组件中管理 state,通过 props 下发给各子组件,子组件通过回调方式,进行通信
这会存在什么问题?你会发现如果你想共享数据,你得把所有需要共享的 state 集中放到所有组件顶层,然后分发给所有组件。
为此,需要一个库,来作为更加牛逼、专业的顶层 state 发给各组件,于是,我引入了 redux。
redux 体验
redux 可以说是较成熟,生态圈较完善的一个库了,搭配 redux-devtools-extension 这个 chrome 插件,让你开发更加快乐。然,世间万物,皆有利弊。
本身我使用 redux 并不会有什么所谓的“痛点”,因为 redux 默认只支持同步操作,让使用者自行选择处理异步,对于异步请求 redux 是无能为力的。可以这么说,它保证自己是纯粹的,脏活累活都丢给别人去干。
于是我的痛点在于 : 如何处理异步请求,为此我使用了 redux-saga 去解决异步的问题
但是在使用
redux + redux-saga
中,我发现,这会让我的 [重复性] 工作变多(逐步晋升 CV 工程师),因为它在我们项目中,会存在啰嗦的样板代码。举个 🌰 : 异步请求,获取用户信息,我需要创建
sagas/user.js
、reducers/user.js
、actions/user.js
,为了统一管理 const,我还会有一个const/user.js
,然后在这些文件之间来回切换。没错, 这种样板代码,简直就是 CV 操作,只需要 copy 一份,修改一下名称,对我个人而言,这会让我不够专注,分散管理 const、action、saga、reducer 一套流程,需要不断的跳跃思路。
而且文件数量会变多,我是真的不喜欢如此
繁琐
的流程,有没有好的框架能帮我把这些事都做完呢?dva
dva,基于 redux 和 redux-saga 的数据流方案,让你在一个 model 文件中写所有的
action、state、effect、reducers
等,然后为了简化开发体验,内置了 react-router 和 fetch.聊聊我对 dva 的看法,官方说了,基于
redux
+redux-saga
的方案,只是在你写的时候,都写在一个 model 文件,然后它帮你做一些处理;其次它是一个框架,而不是一个库,是否意味着: 我在项目开始之前,我就需要确定项目的架构是不是用 dva,如果开发一半,我想换成 dva 这种状态管理的写法,而去引入 dva ,是否不合理?再或者,我只是做一些 demo、写点小型的个人项目,但我又想像写 dva 的数据状态管理 model 那种方式,引入 dva 是不是反而变得笨重呢?
回过头来看,我的出发点是 : 在于解决繁琐重复的工作,store 文件分散,state 类型和赋值错误的问题,为此,对于跟我一样的用户,提供了一个写状态管理较为[舒服]的书写方式,大部分情况下兼容原先项目,只需要安装这个包,就能引入一套数据管理方案,写起来又舒服简洁,开心开心的撸代码,不香吗?
再次明确
rc-redux-model 出发点在于解决繁琐重复的工作,store 文件分散,state 类型和赋值错误的问题,为此,对于跟我一样的用户,提供了一个写状态管理较为[舒服]的书写方式,大部分情况下兼容原先项目~
action、state、reducers
[model.namespace/setStore]
即可,从而将一些重复的代码从 model 文件中剔除初建雏形
由于之前看过 redux 源码,同时也看了一下 redux-thunk 的源码,并且查阅了一些相关文章,有了一些知识储备,说干就干~
参考了 dva 中对 model 的参数说明,因为我没有了 redux-saga ,所以是没有
effect
这个属性的,于是初步得到我的 model 参数按照我的设想,我会存在多个 model 文件,聚集在一起之后,得到的是一个数组 :
我所希望的是 : 传入一个
Array<IModelProps>
,得到一个RcReduxModel
对象,该对象拥有得给我导出 :store.combineReducers
中了,同时可以兼容你现有的项目,因为只要你用了 redux, 那么你肯定得通过combineReducers API
去集合所有的 reducers因为我想像写 model 那样,所有东西都在一个文件中,自然而然,这个 action 集到 model 里边之后,如何处理异步就成了我需要解决的一个问题
异步处理
这里我可以将
redux-thunk
或者redux-saga
集成进去,但是没必要。出于对这两个库的学习,以及在使用上带给我的[体验],我在想,能不能自行处理?然后给其添加自己的特色和功能?于是,我去将
redux-thunk
的源码看了一遍,最后得出了一个解决方案 : 对比 redux-thunk ,其内部在于判断你的 action 是 function 还是 object,从而判断你的 action 是同步还是异步;而在rc-redux-model
中,甭管三七二十一,我规定的每一个 action 都是异步的,也就是你发起的每一个 action,都是函数 :即使你想要发起一个同步 action,去修改 state 的值,我也会将其作为异步进行处理,也就是你修改 state 值,你需要这么写 :
明确了这两点,接下来就只需要开发即可。如果前边看过我写 redux 源码分析到话,可以知道 reducer 是一个纯函数,所以我注册 reducer 中时,一定要明确这点: (以下代码摘抄 rc-redux-model 源码)
其次是对于中间件的开发,每一个中间件都是
store => next => action
的形式(不太了解中间件的可以自行去了解一波),所以我很简单就可以写出这段代码 :上边是摘抄了部分源码,感兴趣的小伙伴可以去看看源码,并不多,并且源码中我都写了注释。经过不断调试,并且通过 jest 写了单元测试,并没有啥毛病,于是我兴致勃勃得给身边的同事安利了一波,没想到被 👊 打击了
提供默认行为,自动注册 action 及 reducers
“只有被怼过,才能知道你做的是什么破玩意”,在我给小伙伴安利的时候,他问 : “那你这东西,有什么用?”,我说写状态数据像写 dva 一样舒服,于是他又说,那我为什么不用 dva 呢?
解释一波后,他接着说: “不可否认的是,你这个库,写状态数据起来确实舒服,但我作为一个使用者,要在组里推广使用,仅靠此功能,是无法说服我组里的人都用你这个东西,除非你还能提供一些功能。听完你的介绍,你说你的 action 都是异步的,等价于修改 state 的 action,都需要我自己去写,假设我有 20 个 state,意味着我得在 model.action 中,写对应的 20 个修改 state 的 action,然后在 model.reducers 中同样写 20 个相对应的 reducer,作为使用者,我的工作量是不是很大,如果你能提供一个默认的 action 行为给我,那么我还可能会用”
仔细一想,确实如此,那我就提供一个默认的 action,用于用户修改 state 的值吧,当我提供了此 action 之后,我又发现,所有修改 state 的 action,都走同一个
action.type
,那么在 redux-devtools-extension 中,是很难发现这个 action 触发,具体是为了修改哪个 state 值。但是正如使用者说的,如果有 20 个 state 值,那么我为用户自动注册 20 个 action,用户在使用上是否需要记住每一个 state 对应的 action 呢?这肯定是极其不合理的,所以最终解决方案为 : 为每一个 state ,自动注册对应的 action 和 reducer, 同时再提供了一个默认的 action(setStore)
用户只需要调用默认提供的
setStore
即可,然后根据 key 进行判断,从而转发到对应到 action 上 ~ 使用起来极其简单数据不可变
在函数式编程语言中,数据是不可变的,所有的数据一旦产生,就不能改变其中的值,如果要改变,那就只能生成一个新的数据。在我的项目中,我使用了
seamless-immutable
,那么在 model.state 中,我使用了 Immutable 包裹了 state,然后调用默认提供的 action,最后会报错,懂的都懂 !那么该怎么办呢?于是...我又在内部支持了 Immutable ,提供一个配置参数 openSeamlessImmutable,默认为 false,请注意,如果你的 state 是 Immutable,而在 model 中不设置此配置,那么会报错 !!!
进一步处理类型不一致
不可避免,开发人员会存在一定的疏忽,有时在
model.state
中定义好某个值的类型,但在改的时候却将其改为另一个类型,例如 :但在修改此 state value 时,传递的确是一个非 string 类型的值
这其实是不合理的,在 rc-redux-model 中,会针对需要修改的
state[key]
做一些类型检测处理,如 👍所有修改 state 的值,前提是 : 该值已经在 state 中定义,以下情况也会报错提示
此时想修改 state 中的另一属性值
极度不合理,因为你在 state 中并没有声明此属性, rc-redux-model 会默认帮你做检测
结尾
到此,终于将一套流程走完,同时在组里的项目拉了个分支,实践使用了一波,完美兼容,未出问题。于是交付了第一个可使用的版本,这次一个中间件的开发,让我对 redux 的了解更近异步,最后,👏 欢迎大家留言一起交流
The text was updated successfully, but these errors were encountered: