vlambda博客
学习文章列表

如何编写漂亮的React代码?

作者 | Vinícius Andrade
译者 | 张健欣
策划 | 田晓旭

React 代码很难看。我不是在谈论这个框架的任何技术特性;我说的是直观的美学,代码在我屏幕上的样子,以及它所唤起的感觉。

代码美学通常并不是开发人员关注的问题。我们要操心更重要的问题。美学是主观的,很难衡量,追求它的好处也并不明确。你很少会看到一个开发人员举手在站例会上告诉他们的同事他们对代码在屏幕上的样子不满意。我不确定是否有人会这么做,但我的看法有所不同。

我是在从事一个副业项目时,开始考虑 React 的美观问题的。作为大多数以编码为职业和爱好的程序员,工作和休闲之间的区别是由你所享受到的快乐所决定的。当然,我们的职业生涯目标是让这两者一致,尽管有时候这两者是一致的,但是当这两者不一致时,你仍然希望你的“编码放松”时间尽可能地愉悦。

当然,如果出于某种原因,React 对我来说是不愉快的,而我想要花时间编写代码来获得乐趣,那么最明显的做法就是不要使用 React。而我大多数时间就是不用 React 的。但是,众所周知,编码是多方面的:你有代码、工件、你向计算机输入的符号行,但你也有代码结果,它的输出,你用编程语言表达的想法的现实意义。可以从我的代码与现实世界的交互中获得同等甚至更大的乐趣,我对此比较在乎。

结果是,尽管有时我发现一种编程语言、框架、工具不太好看或不好用,但我需要它来在合理的时间内让我的代码描述现实的某件事。也许这就是大型社区围绕这些工具创建东西的原因,或者其它一些技术特性。不管什么原因,我的编码作为业余爱好的时间很少,而且尽管我想让它变得愉快,但我也希望充分利用这些时间,这意味着使用不总是符合我的审美标准的东西。React 就是这样的东西。

有一天,当我思考这个话题的时候,突然想到一个问题:我能在保持高生产力的同时,写出既美观又令人愉悦的 React 代码吗?我知道在其它编程语言和框架中,这个问题有非常有价值的答案。所有那些方法都会有不同程序的相同权衡,例如学习难度、能从 React 生态系统获益的多少、围绕它的工具如何等等。所有这些权衡都要根据项目的目标进行不同的衡量。

我对这个问题的答案通常是一些非 React 的其它东西。但每隔一段时间,你会比较每一个权衡;你从不同的角度看待你的项目;你试着重新考虑你设想的特性和你的需求;最后,React 会是你的答案。考虑到这些情况,我将原来的问题重新设定为:“在保持 React 代码不变的同时,我还能在多大程度上使 React 代码更好看?”

“在保持 React 代码不变的同时,我还能在多大程度上使 React 代码更好看?”

为了开始回答这问题,我创建了一个 Create React App 项目,使用了一些简单的 React 代码作为参考。我希望它有一点儿抽象,足够简单,这样就不会妨碍测试不同的东西。我选择了官方的 React 教程代码,你可以在这里找到:

https://codepen.io/gaearon/pen/gWWZgR?editors=0010

聚焦这段代码的最简单的 React 组件,Square 组件,我们看到如下代码:
function Square(props) {
 return (
   <button className=”square” onClick={props.onClick}>
     {props.value}
   </button>
 );
}

而这就是比较主观的一点:我对这段代码很不满意。我不是在讨论这段代码的技术属性。当我说它难看的时候,我只是在试图表达它在我心中唤起的一套感觉,而这在很大程度上是基于我对世界的总体体验,特别是编程。从这个角度来看,第一个让我抓狂的问题是 JSX。

自从 JSX 推出以来,它已经被讨论了很多,但是为了阐明我的观点,我将快速说明一下。JSX 很混乱,但它也是一种现实产物。它源于前端技术的自然演变,从一开始就有某种形式的 XML 语言来定义标签。不同之处在于,JSX 通常位于 JavaScript 代码中。

与口语语言进行粗略的类比,JSX 就好像某一特定语言的使用者开始使用其它语言的一整套单词和短语来表达自己。例如,当一个特定的主题是某一特定文化所固有的时候,这种情况就经常发生。当文化之外的人,说不同语言的人,面对表达关于这个主题的想法的挑战时,他们通常会缺乏词汇来处理这个问题,重复使用那些“产生”这个话题的人所说的语言来解决这个问题。语言纯粹主义者很快就会生气,指出你怎么能不需要外来词汇就可以说那些话题。但人们仍然会使用这些词,其中一些词最终会被纳入官方语言。JSX 诞生于 JavaScript 开发人员对于表达 UI 标签的需要。

继续上面语言使用者的类比,一些灵魂将语言用于审美目的和自我表达。诗人和文学作家通常就是这样。他们如何看待外语单词?好吧,他们毫无疑问会有不同的看法。他们的观点与我这里的观点类似,因为这不仅从语言表达思想的能力来看待语言,同时还从美学角度考虑。从这个角度来看,JSX 的使用是不必要的:它增加了噪音,并且对于它表达思想没有帮助。

所有这些都是说,我朝着一种更愉快的方式编写 React 的第一步就是摆脱 JSX。

无 JSX 版本的 button 组件如下所示:
const e = React.createElement;
function Square({ onClick, value }) {
  return e(‘button’, { className: ‘square’, onClick }, value);
}
代码的一致性和简洁性带来了实质上的美学提升。而且我们可以在无 JSX 路上走得更远。我远不是第一个讨论是否采用 JSX 的人。对于 JSX 的厌恶可能和 JSX 本身一样古老。我打赌 JSX 最初的团队至少有人说过这是不必要的。你会发现大量关于 JSX 糟糕的原因以及不使用 JSX 的好处的阅读资料。令人高兴的是,你也可以找到技术上的替代品。一个突出的例子是 Hyperscript,它是 React 团队 在他们的文档中 推荐的。这是一个简单的工具,可以帮助你使用 JavaScript 构建超文本。它的 React 版本带来了比 createElement 更吸引人的 API。我决定将它与一个称作 hyperscript-helpers的小工具库一起使用试试,我发现这些工具对代码美观的贡献相当不错:
function Square({ onClick, value }) {
  return button({ className: ‘square’, onClick }, value);
}

取代 JSX 是帕累托原则在 React 代码美观方面的应用。省力,效果好。如果想要更漂亮的 React 代码,每个人都应该采取行动。继续探索如何在框架领域美化 React 代码,我发现了一个死胡同。虽然我可以探索一些设计模式和简单的惯例,但它们需要根据具体情况评估它们的技术含义,而我正在寻找更通用的方法。因此,下一步需要在 JavaScript 层探索。

JavaScript 是一种非常灵活的语言,这是一把双刃剑。这也可以从美学角度来探索。有许多不同的方法可以编写有效的代码,但会有明显的风格差异和技术意义。许多工具可以帮助你自定义和强制你所选择风格,在这些工具中,我最喜欢:StandardJS。StandardJS 是一个用于自动将一系列合理的编码样式选择应用到你的代码的一个工具。在这些选择中最具有美学意义的一点是去掉了分号。

我发现,分号在 JS 代码中是一种不必要的噪音,我很乐意冒险不使用它们。在我将 StandardJS 合并到我的参考示例后,是下面这样:
function Square ({ onClick, value }) {
  return button({ className: ‘square’, onClick }, value)
}

现在就 JavaScript 代码而言,这是我所能得到的最好的代码了。回顾到目前为止我所做的东西,一切看起来还都不错。这些更改实现很简单,可以很容易地集成到我的默认副业项目的 React 配置中。另一方面,这在美学上与我在其它不同语言中的体验仍然相去甚远。我已经讨论过其它语言的情况,重点是我想在 JS 世界中使用 React。除非有什么东西能给 JavaScript 增添一些优雅的光彩,同时又保持 JavaScript 的样子,否则很难达到我设定的界限。

“就像 JavaScript 一样。”当试图发挥我的创造力去寻找不同的可能性时,这句话让我回到了十年前。我正在学习 Web 开发,而且刚刚碰到 Ruby on Rails。那时,Rails 在发布时通常会内置附带一种不同类型的 JavaScript,称作 CoffeeScript。CoffeeScript 有一条黄金法则:“这只是 JavaScript。”就是那样,CoffeeScript 可以满足我的标准,因此我决定看看这个项目进展如何并尝试一下。

我知道,自从 ES5 以来,CoffeeScript 的一些好的特性被整合到 JS 标准中,因此从技术上讲,人们采用 CoffeeScript 的理由更少了。随着编译器的出现,使得每个人都可以使用甚至还不是标准的 JS 特性,即使是不得不支持旧浏览器的开发人员现在也可以从最新的语言特性中受益。这使得 CoffeeScript 的流行程度大不如前。但是我的兴趣不是技术性的。我想找到一个令人愉快的美学方案,使得我可以编写看起来不错的 React 代码,同时还是 JavaScript,而不需要学习一种新语言或者框架。

从文档来看,CoffeeScript 与 JavaScript 非常接近,我可以忽略学习曲线,而且它在美学方面给代码带来了显著改进。我一直怀疑它是否还在维护,事实证明它确实还在维护。其最新版本在今年初完成。它的最新主版本包含了新的 JS 特性,甚至支持 JSX。因此,我决定将它集成到我的示例项目中。为此,我不得不将我的 Creact React App 配置弹出,这样我就可以为 CoffeeScript 增加一个 Webpack 加载器。除此之外,转换非常简单。

这就是设计的 Button 组件最终代码的样子:
Square = ({ onClick, value }) -> 
 button ‘.square’, { onClick }, value

如果你对整个代码最终的样子感到好奇,你可以在这里找到它:

https://github.com/vicnicius/beautiful-react-example/blob/master/src/App.coffee

在美学方面,我认为这个代码对于我最初的代码是巨大的进步。语法简洁,看起来干净。

关于美的追求,更少就是更美,人们已经说了很多。我很认同这一点。结果发现,我的美观探索基本上就是用更少的 React 代码表达思想。CoffeeScript 带来的卓越改进——也是其它语言使用的方式——就是去掉无意义的标记。这种认识在最后会很明显,但最初不怎么明显。它的目的是总体上增强 less 的力量。

从务实的角度来看,乍一看,采用这种风格似乎不会影响生产力。CoffeeScript 推出已经有一段时间了,而且我期望它有一些像样的工具。我在做这个快速实验时没有感到意外。不过,有一件事让我无法完全采用它:那就是与 TypeScript 一起使用的能力。我知道如何让它起效,但是我决定在这一点上停止探索。不管怎样,如果你喜欢这个情景,就会有兴趣采用相似的方案,并且会对它如何与 TypeScript 一起工作感到好奇,可以留言告诉我。

感谢您的阅读。

总结: 从代码美学的角度来看,Hyperscript 和 CoffeeScript 的结合是编写漂亮的 React 代码的一种很好的方式。

作者介绍

Vinicius Andrade,学会编码,学会思考,学会行动,学会等待——在 https://vicnicius.com 记录所思所感。

延伸阅读

https://medium.com/javascript-in-plain-english/writing-beautiful-react-code-using-a-good-old-mate-ca1450c0dc06