[译] 更可靠的 React 组件:清楚易懂的可表达性

2020-06-15 22:12:47 浏览数 (2)

原文摘自: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> -- 根据你的喜好来,只要保持一致性就好。

注释

意义明确的组件名称、方法名及变量名,已经足以让代码可读。在这种情况下,注释就已经多余了。

案例学习:编写自解释型的代码

常见滥用注释情况就是,对没有意义而含糊的命名进行解释。看看下面的案例:

代码语言:javascript复制
// <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>datadata1v、魔法数字 10都是没有意义而难以理解的。

如果把组件重构,让其拥有意义明确的 props 和变量,则注释就可以轻易的省去了:

代码语言:javascript复制
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 种层次。所处的层次越低,则理解组件需要付出的努力就越多。

可以从以下方面理解组件的用途:

  1. 阅读命名和 props
  2. 求助于文档
  3. 浏览代码
  4. 询问作者

如果命名和 props 提供了组件之于应用的足够信息,那就是一种强表达性。要努力保持这种高水准。

有些组件具有复杂的逻辑,甚至良好的命名也无法表达出必要的细节。此时求助于文档就是个好习惯了。

当文档也有所缺失或是无法回答所有问题是,就不得不浏览一下代码了。虽说因为增加了额外的时间成本而算不上最好的选项,但这也是可以接受的。

而通读了代码后仍看不懂组件的话,下一步就要像组件的作者询问其细节了。这一步肯定是要尽量避免的。更好的做法是请求作者重构其代码,或是你自己(译注:确定弄清楚后)动手重构。

0 人点赞