重复代码不是我们的敌人, 脆弱的抽象基础才是.
很多时候, 一个个 “小小的需求改动”, 之所以要弄很久, 不是我们需要复制粘贴改十遍, 而是我们改了一个地方, 其他九个地方出问题了.
如果所有的需求都能负责粘贴改就做完, 那么程序员也不会掉头发.
vuex/redux 是用来放全局状态的, 如果一个数据是不是全局状态, 那么它不应该放在 vuex/redux 里.
应当避免污染全局状态, 这就是为什么我们不应当把很多东西都挂载在 window 对象上, 为什么 ES6 引入模块, 为什么用 var 声明变量已经被淘汰了的原因.
问:
但是组件 A 和组件 B 都依赖了数据 C, 如果不把数据放在全局状态里, 那么数据会请求两次.
答:
- “但是组件 A 和组件 B 都依赖了数据C” 不等价于 “数据 C 是全局状态”, 只能说明数据 C 在某一个特定的范围内是共享的. 在确定了数据C的共享范围(比如组件 A 和组件 B都在共同父组件)之后, 可以将数据 C 的获取, 维护写在这个特定的范围内(React.Context).
- 组件 A 和组件 B 都用到了数据 C 不等价于 都依赖 了数据C. 举个例子, 组件 A 和组件 B 都实用了 goods[id=1] 的数据, 单它们的 id, 不来自同一个变量, 只是在当前 恰好 值一样, 那么数据 C 不应该抽象为一个公共状态.
在面向对象编程中, 一个常见的错误是将两个相似的东西抽象为一个基类.
因为狗狗和汽车都借助 轮子/腿 走路, 于是Dog extends Card, 我们发明了狗狗车.
因为猫猫和毛毛虫都有毛, 所以我们发明了猫猫虫.
但其实继承不是说 A 像 B, 而是 A 是 B, Dog extends Animal 是因为狗是一种动物.
相似是脆弱的, 易变的, 不是所有的猫猫都有毛的, 在脆弱的基础上抽象, 最终我们得到的不是代码复用, 而是代码耦合.
耦合的代码最终导致了 “改了这个, 那个又不行了”.
而全局状态, 便是一种最强的耦合.
由于时间不足, 这个文章只是开个头, 这里先记下TODO:
- 说明 将数据放在全局状态里, 不是真的复用, 要想复用, 还需要将这些数据与请求的参数(key)进行绑定, 并进行缓存过期管理, 并最终 “发明” 了 react-query.
- 说明 React.Suspense 是如何用声明式的写法, 简化了数据 loading, error 的处理的.
- 说明 为什么要选择 显式地声明, 而不是 隐式 的魔法, 并以 mixin 为例, 说明 mixin 这种为了复用而带来的 隐式 的魔法的危害, 并最终被 React 社区弃用.
- 说明 什么是严谨的代码, 为什么我们应当在代码中基于 脆弱 的前提条件 把代码写死.