共计 4237 个字符,预计需要花费 11 分钟才能阅读完成。
造梦者之梦语:
很多事情努力了未必有结果,但是不努力却什么改变也没有。
故事旁白:
曾经有个少年,怀揣着一个梦,踏入一个叫做 IT 的圈子,从此明白江湖无容易二字。
社会如激流,如不勇进,终将被推下万丈深渊。
如果你能看到这篇文章,恭喜你,已经走到了第四章了,请坚持下去,会有收获的
主题预热:
本次锵哥将带大家了解一下,一个 react 项目,如何从一个应用的维度去思考跟设计,文章内容也会越来越开始深入,如果有心学,请认真阅读,这终将转化为你自己的能力筹码。
正文:
章节:《深入浅出 React 和 Redux》(第四章:模块化 React 和 Redux 应用)
1. 创建一个复杂一点的应用该如何做:
A: 模块化应用的要点
B: 代码文件的组织方式
C: 状态树的设计
D: 开发辅助工具
2. 从架构出发,当我们开始一个新的应用,有几件事情是一定要考虑清楚:
A: 代码文件的组织结构
B: 确定模块的边界
C:Store 的状态树设计
3. 确定了我们的应用要做什么之后,不要上来就开始写代码,磨刀不误砍柴工,先要考虑上面提到的三个问题。
4. 代码文件的组织方式:
A: 按角色组织
B: 按功能组织
5. 例如 MVC 按角色组织,分为 controllers,models,views
6.Redux 应用中有一种代码组织方式就是按角色组织,分为 reducer(目录包含所有的 Redux 的 reducer),actions(目录包含所有 action 构造函数),components(目录包含所有的傻瓜组件),contains(目录包含所有的容器组件)
7. 在互联网上,很多教学资料也是按照“按角色组织”的方法管理 Redux 应用。虽然“按照角色组织”的方式看起来不错,但是实际上非常不利于应用的扩展。
8.Redux 应用适合于“按功能组织”(Organzied by Feature),也就是把完成同一应用功能的代码放在一个目录下,一个应用功能包含多少个角色的代码。
9. 每个目录包含角色文件:
A:actionTypes.js 定义 action 类型
B:action.js 定义 action 构造函数,决定了这个功能模块可以接受的动作
C:reducer.js 定义这个功能模块如何响应 action.js 中定义的动作
D:views 目录,包含这个功能模块中所有的 React 组件,包括傻瓜组件和容器组件
E:index.js 这个文件把所有的角色导入,然后统一导出
10. 表面上看来,“按照角色组织”还是“按照功能组织”只是一种审美的问题,也许你觉得自己已经习惯了 MVC 世界的“按照角色组织”方式,也许你已经有一套很厉害的代码编辑器可以完美解决在不同目录下寻找代码文件困难的问题。但是,开发 Redux 应用你依然应该“按照功能组织”的方式,为什么呢,我们看看下一条“确认模块的边界”就明白了
11.“在最理想的情况下,我们应该通过增加代码就能增加系统的功能,而不是通过对现有代码的修改来增加功能”
12. 模块之间有依赖关系的时候,直接导入对方内部的文件非常不合理,因为这让 filter 模块依赖于 todoList 模块的内部结果,而且直接伸手到 todoList 内部去导入想要的部分
13. 现在既然我们把一个目录看做一个模块,那么我们要做的是明确这个模块对外的接口,而这个接口应该实现把内部封装起来
14. 如果 filter 中的组件想要使用 todoList 中的功能,应该导入 todoList 这个目录,因为导入一个目录的时候,默认导入的就是这个目录下的 index.js 文件,index.js 文件中导出的内容,就是这个模块想要公开出来的接口
15.ES6 语法中,export default 和 export 两种导出方式的导入方式也会不同
16. 无论使用哪种导出方式,都请在整个应用中只用一种模块导出方式,保持一致,避免混乱
17. 因为所有的状态都存在 Store 上,Store 的状态树设计,直接决定了要写那些 reducer,还有 action 怎么写,所以是程序逻辑的源头
18. 状态树设计要遵循几个原则:
A: 一个模块控制一个状态节点
B: 避免冗余数据
C: 树形结构扁平
19. 一个状态节点只属于一个模块,比如,如果 A 模块的 reducer 负责修改状态树上 a 字段下的数据,那么另一个模块 B 的 reducer 就不可能有机会修改 a 字段下的数据。
20. 这里所说的“拥有权”指的是“修改权”,而不是“读取权”,实际上,Redux Store 上的全部状态,在任何时候,对任何模块都是开放的,通过 store.getState()总能够读取当前整个状态树的数据,但是只能更新自己相关那一部分模块的数据。
21. 冗余数据是一致性的大敌,如果在 Store 上存储冗余数据,那么维持不同部分数据一致就是一个大问题
22. 在前端 Redux 的 Store 中,一定要避免数据冗余的出现
23. 即使使用“范式化”的无冗余数据结构,我们借助 reselector 等工具一样可以获得很高的性能
24. 理论上,一个树形结构可以有很深的层次,但是我们在设计 Redux Store 的状态树时,要尽量保持树形结构的扁平
25. 这是 Redux 最有意思的一部分,虽然 Redux 的 createStore 只接受一个 reducer,却可以把多个 reducer 组合起来,成为一体,然后就可以被 createStore 函数接受
26. 我们使用了 Redux 提供的一个函数 combineReducers 来把多个 reducer 函数合成为一个 reducer 函数
27. 我们来总结一下 Redux 的组合 reducer 功能,利用 combineReducers 可以把多个只针对局部状态的“小的”reducer 合并为一个操作整个状态树的“大的”reducer,更妙的是,没有两个“小的”reducer 会发生冲突,因为无论怎么组合,状态树上一个子状态都只会被一个 reducer 处理,Redux 就是用这种方法隔绝了各个模块
28. 使用 ref 实际上就是直接触及了 DOM 元素,与我们想远离 DOM 是非之地的想法相悖,虽然 React 提供了这个功能,但是还是要谨慎使用,如果要用,我们也尽量让 ref 不要跨越组件的边界
29. 我们并不能在 JSX 中使用 for 或者 while 这样的循环语句。因为 JSX 中可以使用任何形式的 JavaScript 表达式,只要 JavaScript 表达式出现在符号 {} 之间,但是也只能是 JavaScript“表达式”,for 或者 while 产生的是“语句”而不是“表达式”,所以不能出现 for 或者 while
30. 归根到底,JSX 最终会被 babel 转译成一个嵌套的函数调用,在这个函数调用中自然无法插入一个语句进去,所以,当我们想要在 JSX 中根据数组产生动态数量的组件实例,就应该用数据的 map 方法。
31. 实际上,Redux 已经提供了一个 bindActionCreators 方法来消除这样的重复代码,显而易见很多 mapDispatchToProps 要做的事情只是把 action 构造函数和 prop 关联起来,所以直接以 prop 名为字段名,以 action 构造函数为对应字段值,把这样的对象传递给 bindActionCreators 就可以了。
32. 更进一步,可以直接让 mapDispatchToProps 是一个 prop 到 action 构造函数的映射,这样连 bindActionCreators 函数都不用
33. 我们使用了一个特殊的属性 children,对于任何一个 React 组件都可以访问这样一个属性,代表的是被包裹住的子组件。
33. 毫无疑问,ref 的用法非常脆弱,因为 React 的产生就是为了避免直接操作 DOM 元素,因为直接访问 DOM 元素很容易产生失控的情况,现在为了读取某个 DOM 元素的值,通过 ref 获取对元素的直接引用,不得不说,干得并不漂亮
34. 在产品开发中,应该尽量避免 ref 的使用,而换用这种状态绑定的方法来获取元素的值
35. 开发辅助工具,Chrome 扩展包
A:React Devtools, 可以检视 React 组件的树形结构
B:Redux Devtools,可以检视 Redux 数据流,可以将 Store 状态跳跃到任何一个历史状态,也就是所谓的“时间旅行”功能
C:React Perf,可以发现 React 组件渲染的性能问题。
36. 我们曾经反复强调过,每个 reducer 函数都必须是一个函数,不能修改传入的参数 state 和 action,否则会让应用重新陷入状态不可预料的境地,
37. 禁止 reducer 函数修改参数,这是一个规则,规则总是会被无心违反的,但是怎么避免开发者不小心违反这个规则呢,
38 有一个 redux-immutable-state-invariant 包,提供了一个 Redux 的中间件,能够让 Redux 在每次派发动作之后做一个检查。如果发现某个 reducer 违反了作为一个纯函数的规定擅自修改了参数 state,就会给一个大大的错误警告,从而让开发者意识到自己犯了一个错误,必须要修正
39. 对于 React Devtools 来说,启用只是安装一个 Chrome 扩展包的事,但是对于其余几个工具,我们的代码要做一些修改才能配合浏览器使用
40. 在这里把 window 赋值给模块级别变量 win,是为了帮助代码缩小器(minifer),在 webpack 中缩小代码的插件叫 UglifyJsPlugin,能够讲局部变量名改成很短的变量名,这样功能不受影响但是代码的大小大大缩减。
41. 为了应用 redux-immutable-state-invariant 中间件和 Redux Devtools,需要使用 Redux 的 Store Enhancer 功能。
42. 因为 Store Enhancer 可能有多个,在我们的例子中就有两个,所以 Redux 提供了一个 compose 函数,用于把多个 Store Enhancer 组合在一起。
观后感回放:
粉丝路人甲:“锵哥今天好严肃,我怕”
锵哥:“别怕,当你发现看不懂的时候,就是你开始获得成长的时候”
粉丝路人甲:“嗯,我会坚持的”
锵哥:“加油!”
粉丝路人甲:“”
广告:
本人从事全栈工程师,目前主要工作能力涵盖的范围有:android,ios,h5,pcWeb,react,vue,node,java 服务端,微信服务号,微信小程序,支付宝生活号,支付宝小程序。
本公众号会不定期的将自己的研发感悟,以及心得笔记无私奉献给大家。还等啥,赶快上车吧,铁子们!!!????(还会有其他的福利哦!快来吧)
官方订阅号:锵哥的觉悟
微信号:DY_suixincq
二维码: