React实战
上QQ阅读APP看书,第一时间看更新

1.2 React不能做什么

到目前为止,我已经从较高层次探讨了React:谁使用React,本书面向的人群,以及其他一些内容。我写本书的主要目的是教人使用React创建应用并使其成为一名工程师。React并不完美,但用其工作真的是一种乐趣,我已经看到很多团队用它做了很多伟大的事情。我喜欢写关于它的文章,用它进行创造,在会议上听到关于它的讨论,偶尔参与关于这个或那个模式的激烈辩论。

但如果不谈论React的缺点并说清它不能做什么,那我就是在帮倒忙。理解某物不能做什么和理解它能做什么同样重要。为什么?最好的工程决策和思考通常基于权衡取舍而不是基于个人观点或绝对真理(React从根本上就比工具X更好,因为我喜欢它)。就前者而言,可能不是在比较两种完全不同的技术(COBOL和JavaScript),甚至很大可能没有考虑那些根本不适合当前任务的技术;而对于后者,创建伟大的项目和解决工程挑战永远不应该跟个人观点有关。并不是人们的观点不重要(这当然不是事实),而是个人观点并不能让事情变得更好,甚至可能完全没有任何作用。

React的权衡

如果权衡是良好软件评估和讨论的基本,那么React中有什么权衡?首先,React有时被称为“只是视图”。这可能会被误解,因为它会让人认为React只是一个像Handlebars或Pug(曾用名Jade)的模板系统,或者它必须是MVC(模型-视图-控制器)架构的一部分。这都不对。React可以是这两种东西,但它可以做得更多。为了让事情更简单,我将更多地用React是什么而非React不是什么来描述React,例如,“只是视图”。React是一个声明性的基于组件的库,用于构建在各种平台上,甚至是未来的虚拟现实平台上(React VR)工作的用户界面:Web、原生、移动、服务器和桌面。

这导致了第一个权衡:React主要关注UI的视图方面。这意味着它并不是通过构建来完成更为全面的框架或库所要做的诸多工作。与Angular这样的框架进行一个快速比较可能有助于真正理解这一点。在最近的主要发布中,较之以前,Angular在概念和设计方面与React有了更多的共同点,但在其他方面,它涵盖了比React更大的领域。Angular包含了下列内置解决方案:

• HTTP调用;

• 表单构建和验证;

• 路由;

• 字符串和数字格式化;

• 国际化;

• 依赖注入;

• 基本数据建模原语;

• 自定义测试框架(尽管这并不像其他领域那样是什么重要的区别);

• 默认包含的服务worker(一种用worker形式来执行JavaScript的方法)。

够多了,以我的经验看,人们对伴随一个框架而来的所有特性通常会有两种反应绝非有意一语双关,看,这是一本关于反应(React)的书,就是这样。。要么类似“哇,我不需要自己搞定所有这些事了”,或者是“哇,我都没法选择自己做事情的方式了”。Angular、Ember这类框架的好处是,它们通常有精心设计的方式来做事。例如,Angular中的路由是由内置的Angular路由器完成的,HTTP任务都是通过内置的HTTP例程完成的,等等。

这种方式没有什么本质上的错误。我曾在使用这种技术的团队中工作过,我也在采用更灵活的方式的团队中工作过,团队会选择“只把一件事做好”的技术。我们用这两种技术都取得了很好的效果。我个人倾向于“自主选择,专精一事”的方法,但这真的不是非此即彼,这只是权衡。对于HTTP、路由、数据建模(尽管它确实对视图中的数据流有自己的看法,我们稍后会看到),或者其他可能在Angular这类框架中看到的东西,React并没有内置的解决方案。如果团队认为没有单一框架就绝对做不了事,那么React可能不是最佳选择。但依我的经验看来,大多数团队都想要React的灵活性以及它带来的思维模型和直观API。

React的灵活方式的一个好处是可以自由地选择对于工作来说最好的工具。不喜欢某个HTTP库的工作方式?没问题,用其他库替换它。想要用不同的方式编写表单?放手去做,没问题!React提供了一组强大的原语。公平地说,其他框架,如Angular,通常也允许把东西换掉,但实际起作用的和社区支撑的做事方式通常是把所有东西内置或包含进来。

拥有更多自由的明显缺点是,如果习惯了像Angular或Ember这样的更全面的框架,那么需要为应用的不同领域想出或者找到自己的解决方案。这是好是坏取决于诸多因素,如团队开发人员的经验、工程管理偏好,以及其他特定于具体情况的因素。“通用型”和“专一型”这两种方式都有非常充分的理由。我更倾向于相信这种方法:将决定或创建正确工具的责任交给团队,随着时间推移去适应和做出灵活的、视情况而定的有关工具的决策。再考虑到无比广阔的JavaScript生态系统——终归会为正在解决的问题找到些东西。但最终,实际上优秀的、高影响力的团队会用这两种方式(有时在同一时间!)来构建他们的产品。

在继续之前,如果不提一下锁定,那就是我的失职了。JavaScript框架很少能真正地相互协作是一个无法回避的事实;通常不能让应用一部分是Angular,一部分是Ember,一部分是Backbone,一部分是React,至少在不细分每个部分或严格控制它们之间的交互的情况下不要这么做。当可以避免这种情况时,把自己置身于这样的处境中通常是没有意义的。通常,人们会在一个特定的应用中使用一个或暂时性地最多使用两个主要框架。

但是当需要改变时会发生什么?如果使用的工具像Angular那样具有广泛的职责,那么迁移应用时可能由于与框架的深度集成而需要完全重写。可以重写应用程序的较小部分,但不能只是替换几个函数就期望一切都正常工作。这正是React的闪耀之处。它使用了非常少的“魔法”方言。这并不意味着它能让迁移变得毫无难度,但它确实有助于摆脱与Angular这样的框架紧密集成所带来的迁移成本——迁移到框架上或从框架上迁移出来。

选择React时需要做出的另一个权衡是,它主要由Facebook开发和构建并且是为了满足Facebook的UI需求。如果你的应用与Facebook应用的UI需求有本质区别,那么使用React可能要吃不少苦头。幸运的是,大多数现代Web应用都在React的技术范围内,但也有一些应用不在此范围内。这可能还包括那些不适用现代Web应用的常规UI范式的应用,或是那些具有非常特殊性能需求的应用(如高速股票行情自动收录器)。然而,即使是这些应用,也可以用React来解决,尽管有些情况下需要更为专门的技术。

我们要讨论的最后一个权衡是React的实现和设计。融入React核心的系统会在组件中的数据发生变化时处理UI的更新。开发人员可以使用被称为生命周期方法的特定方法来挂载进它们执行更改的过程。我会在后面几章中详细介绍这些内容。React处理UI更新的系统使人们更为容易地专注于构建应用能够使用的模块化的、健壮的组件。React将UI与数据保持同步的大部分工作抽象分离出去是其受开发人员青睐的一个重要原因,也是其成为开发人员手中的一个强力工具的重要原因。但还不能说明驱动这个技术的“引擎”没有缺点或没有折中。

React是一种抽象,因此它作为抽象的代价仍然存在。由于React是以特定的方式构建并通过API向外暴露的,开发人员不会对其使用的系统有太多的可见性。这也意味着需要以一种地地道道的React方式来构建UI。幸运的是,React的API提供了“紧急出口”,让开发者可以深入到较低的抽象层级中。人们仍然可以使用jQuery这样的工具,但是需要以一种与React兼容的方式使用。这又是一种折中:一种更简单的思维模型,代价是不能完全以喜欢的方式做所有事情。

开发者不仅会失去对底层系统的一些可见性,还需要为React的行事方式买单。这往往会影响应用栈的一小部分(只有视图而不是数据、特殊的表单构建系统、数据建模等),但仍然会有影响。我希望是人们看到React的好处远远超过其学习成本,并且在使用它时所做的权衡通常会让使用者成为一个更好的开发者。但是,如果我假装React会神奇地解决所有的工程挑战,那就虚伪了。