原文摘自: https://dmitripavlutin.com/7-architectural-attributes-of-a-reliable-react-component/
对于一个 意义明确(meaningful) 的组件, 是易于理解其行为的.
不要低估代码可读性的重要. 你有多少次曾纠结于混乱的代码中, 每个字都看懂了, 但就是猜不出什么意思呢?
相比于真正写代码, 开发者们花费了大把的时间去阅读和理解代码. 编码活动中的 75% 的时间都在理解代码, 20% 的时间用来修改既有的代码, 仅仅只有 5% 的时间是在写新的代码.
把少量的额外时间花费在可读性上, 将减少以后同事和自己的理解时间. 在应用规模增长时, 命名变得重要, 因为代码量越大, 理解起来也越难.
阅读意义明确的代码很容易. 然而要书写有意义的代码, 就要保证代码的整洁, 并且持续努力让自己更条理清楚.
组件命名
Pascal 拼写法
组件名称就是把一个或多个单词 (大部分是名词) 用 Pascal 拼写法 (也称驼峰拼写法 Camel case)串联起来. 比如 <DatePicker>,<GridItem>,<Application>,<Header>.
特殊化
组件越特殊, 其名称中包含的单词可能就越多.
一个叫做 <HeaderMenu> 的组件表示一个头部的菜单; 而叫做 <SidebarMenuItem> 的组件表示边栏中的一个菜单项.
当名称蕴含的意图清楚易懂时, 组件就容易理解了. 为此, 时常要使用冗长的名字. 这是很好的: 冗长总比不清楚好.
假如你从一堆项目文件中分辨出两个组件:<Authors> 和 <AuthorsList>. 仅从名称来看, 你能推测出两者的区别吗? 够呛.
为了弄清楚, 就不得不打开并浏览 <Authors> 的源码. 这样做之后, 你意识到 <Authors> 从服务器请求得到一个作者列表并渲染了 <AuthorsList> 这个表现组件.
给 <Authors> 取一个更特殊化的名字就能避免此情此景, 比如 <FetchAuthors>,<AuthorsContainer> 或 <AuthorsPage> 就都更好.
清楚优于简洁
一词一意
一个词表达一个概念. 比如, 用 list 这个词表示一个渲染过的项目的集合.
为每个概念挑选一个词, 并在整个应用中始终保持这种叙述. 最终将形成一个由曾经使用过的 词语 ->概念 组成的可预测意图映射.
当使用不同的词语去描述同一个概念的时候, 可读性问题就会显现. 举例来说, 你将一个负责渲染订单列表的组件定义为 <OrdersList>, 又将另一个费用列表组件命名为 <ExpensesTable>.
都表示渲染过的项目集合, 但这个同样的概念被表达为了两个截然不同的单词: list 和 table. 并没有理由这样做, 这增加了命名的混乱, 也破坏了一致性.
使用 list 这个词, 将以上组件叫做 <OrdersList> 和 <ExpensesList>; 或是用 table 这个词, 称其为 <OrdersTable> 和 <ExpensesTable> -- 根据你的喜好来, 只要保持一致性就好.
注释
意义明确的组件名称, 方法名及变量名, 已经足以让代码可读. 在这种情况下, 注释就已经多余了.
案例学习: 编写自解释型的代码
常见滥用注释情况就是, 对没有意义而含糊的命名进行解释. 看看下面的案例:
- // <Games> 渲染了一个 games 的列表
- // "data" prop 包含一个 game 数据的列表
- function Games({ data }) {
- // 显示前 10 个游戏
- const data1 = data.slice(0, 10);
- // 把 data1 映射到 <Game> 组件
- // "list" 有一个 <Game> 组件的列表
- const list = data1.map(function(v) {
- // "v" 表示一个 game 数据
- return <Game key={v.id} name={v.name} />;
- });
- return <ul>{list}</ul>;
- }
- <Games
- data=[{ id: 1, name: 'Mario' }, { id: 2, name: 'Doom' }]
- />
例子中的注释用来解释一堆混乱的代码.<Games>,data,data1,v, 魔法数字 10 都是没有意义而难以理解的.
如果把组件重构, 让其拥有意义明确的 props 和变量, 则注释就可以轻易的省去了:
- const GAMES_LIMIT = 10;
- function GamesList({ items }) {
- const itemsSlice = items.slice(0, GAMES_LIMIT);
- const games = itemsSlice.map(function(gameItem) {
- return <Game key={gameItem.id} name={gameItem.name} />;
- });
- return <ul>{games}</ul>;
- }
- <GamesList
- items=[{ id: 1, name: 'Mario' }, { id: 2, name: 'Doom' }]
- />
不要用注释去手动的解释, 而要编写自解释型 (self-explanatory) 和自文档化 (self-documenting) 的代码.
可表达性阶梯
我把组件的可表达性分为了 4 种层次. 所处的层次越低, 则理解组件需要付出的努力就越多.
可以从以下方面理解组件的用途:
阅读命名和 props
求助于文档
浏览代码
询问作者
如果命名和 props 提供了组件之于应用的足够信息, 那就是一种强表达性. 要努力保持这种高水准.
有些组件具有复杂的逻辑, 甚至良好的命名也无法表达出必要的细节. 此时求助于文档就是个好习惯了.
当文档也有所缺失或是无法回答所有问题是, 就不得不浏览一下代码了. 虽说因为增加了额外的时间成本而算不上最好的选项, 但这也是可以接受的.
而通读了代码后仍看不懂组件的话, 下一步就要像组件的作者询问其细节了. 这一步肯定是要尽量避免的. 更好的做法是请求作者重构其代码, 或是你自己 (译注: 确定弄清楚后) 动手重构.
- (end)
- ----------------------------------------
来源: https://juejin.im/post/5b20c8a26fb9a01e6f5622d1