本文翻译自Cory House的博客文章。
React自2013年开源以来,逐步进化演变。当你在网上搜索它时,你会偶尔发现一些讲述过时方法的旧文章。本文就是讲述了团队中编写React组件时需要采取的八项关键决策。
决策1:开发环境
在你编写第一个组件之前,你的团队往往需要在开发环境上达成共识。这里存在很多观点。。。
当然,你可以从头构建一个JS的开发环境。25%的React开发者这么做。我当前的团队使用了create-react-app的一个fork版本,不过添加了一些额外的功能,比如支持CRUD逼真的mock API,可复用的组件库,以及一些代码检查优化处理措施(我们也检查测试文件,而create-react-app是忽略的)。我喜欢create-react-app,但是这个工具会帮助你比较众多具有竞争力的替代方案。想在服务器端渲染?你可以看看Gatsby和Next.js。你甚至可以考虑使用像CodeSandbox这样的线上编辑器。
决策2:Types
你可以忽略类型,可以使用prop-types,使用Flow,或者使用TypeScript。请注意prop-type在React 15.5中被抽成了一个独立的库,所以一些旧文章告诉你的一些import已不再起作用了。
在这个问题上,社区上仍然存在分歧:
我更喜欢用prop-types,因为我发现它在组件内提供了足够好的类型安全性。使用Babel, Jest tests, ESlint, 以及prop-types的组合后,我很难看到运行时的类型错误了。
决策3:createClass还是ES的Class
React.createClass是最初的API,在15.5版本中,它就被弃用了。有些人会觉得转战到ES的class上去有些为时过早。但不管怎样,createClass风格已经从React的核心库中移出去了,取而代之的是React官方文档中“React without ES6”这一页内容。所以这就很清楚了:ES(ECMAScript)的class才是未来。你也可以使用react-codemod把createClass简单地转化成ES的class。
决策4:Class还是Function
你可以使用class或者function来定义React组件。Class用在使用ref和生命周期方法的时候。这里是在可能的情况下考虑使用function的9个理由。不过,function组件也有一些缺点。
决策5:State管理
你可以使用自带的React组件state。它就足够了。状态提升可以很好地运作。或者,你会喜欢Redux或MobX:
我是Redux的粉丝,但是我经常使用自带的React只因为他更加简单。在我当前的角色下,已经交付了十几个React应用了,其中只有两个值得使用Redux。我更喜欢在单个大型应用上发布许多个小型自治应用。
顺便要提到的是,如果你对不可变状态感兴趣,至少有4种状态不可变的状态。
决策6: 绑定(Binding)
在React组件中,至少有六种处理绑定的方法。这主要是因为现代JS语言提供了多种处理绑定的方式。你可以在构造方法(constuctor)里面做绑定,也可以在渲染时做绑定,在渲染方法中使用箭头方法做绑定,使用class属性做绑定,甚至使用修饰符做绑定。可以阅读这篇文章的评论了解更多的选项!每种方法都有它自己的优点,但是假如你可以接受试验性的功能,我建议你使用默认的class属性(又叫做property initializers)。 这个投票是从2016年8月份开始的。到目前为止,它显示了class属性使用人数的增长,以及createClass使用人数的减少。
附注: 一些人对于这个问题很疑惑:为什么render方法里面的箭头方法和数据绑定可以回存在潜在的问题。真实的原因是什么?因为它会是shouldComponentUpdate和PureComponent行为变得古怪。
决策7:样式
在这一点上,选项之间的角逐就变得非常紧张了。有50+种的方式来定义组件的样式,其中包括React的内联样式,传统CSS,Ssss/Less,CSS模块,以及56个CSS-in-JS的选项。不是开玩笑,在样式模块的这门课里,我探索了React定义样式的几种方法,以下就是对应的总结:
红色表示差,绿色表示好,灰色表示警告。
那为什么在React的样式方案选项上有这么多的选择呢?因为没有明显的胜者。
看上去CSS-in-JS正在增长,而CSS模块化正在逐渐失去增长动力。
我当前的团队使用的是Sass,搭配着BEM,这已经蛮愉快了,但是我同样喜欢styled-components。
决策8:可复用逻辑
React最初接受mixin作为组件间分享代码的一种机制。但是mixin导致了一些问题,并且现在被视为是有害的。你不能在ES的class组件中使用mixin,因此现在人们使用高阶组件和render 属性(又称function as child)来在组件间共享代码。
高阶组件现在越来越流行,但是我更喜欢使用render 属性,因为它们往往更加易读易写。Michael Jackson最近给我推销了这个(译者注:youtube,翻不了的话请留言,我后期再换成国内源):
当然,这还不是全部。。。
这里还有更多的决策需要考虑:
- 用js还是jsx扩展名?
- 是否把每个组件放在各自的目录下?
- 是否是一个组件对应一个文件?要不要采用每个目录下放置一个index.js文件这样让人抓狂的形式?
- 如果使用propTypes,那是在class自身内使用静态属性,还是在底部声明它们?是否要将propType定义的足够深?
- 是按传统的方式在constructor里面初始化state,还是利用属性初始化器语法?
因为React大多数情况下还是JavaScript,你同样需要考虑一份JS开发规则的常规决策清单,比如分号,逗号,格式,以及事件处理器的命名等等。
选择一个标准,然后自动化执行
关于上面的这些内容,你在野蛮生长的现如今可能会看到几十种组合。
那么,接下来几步就是关键了:
- 在团队内讨论这些决策,并且将标准定义成文档。
- 不要在代码审查(code review)时浪费时间人工检查这些。应该用像ESLint, react-codemod,prettier这样的工具自动验证你的标准。
- 需要重建已有的React组件? 使用react-codemod来自动化这个过程。
如果我还忽略了什么关键决策,请在下面的评论中指出。