为什么我从 Angular 转向 React

2,469 阅读9分钟
原文链接: www.oschina.net

在过去的一段日子里我大量地使用了 Angular 1.x,直到我开始使用 React。这两个项目我使用得比较广泛。但是,其中有几个原因使我转向了 React。刚开始原因还不是那么清晰,但现在回顾起来,我认为我可以对此作出一个很好的总结了。

为什么我从 Angular 迁移到 React?我给出了 10 个理由。过去我喜欢 Angular 的各个方面,但是该是时候移除它了。这篇文章帮助人们理解 React 的优点, 也会让人们了解 Angular 的优点,之后,再让人们在 Angular 或 React 间作出选择,或甚至是在 React 与 Angular 2 间作出选择。

本文并不打算批判 Angular。 长期以来,对我来说 Angular 具有很优秀的单页应用程序体验。 我喜欢这个框架,因为它给你所需要的一切。 由于我只是广泛使用过 Angular 1.x,所以本文不打算谈论 Angular 2,但我认为大多数的框架背后的原理仍然是相同的,本文所述同样适用于 Angular 2。最后,在此我仅关于这两种解决方案提供我的个人经验。

文章不是对两种解决方案进行比较,而是关于为什么考虑使用 React 作为解决方案的反思。 比较苹果和橘子是毫无意义的。 但是,反思你为什么可以使用或你为什么选择了一个特定的工具却是有意义的。

接下来让我们来看看我现在喜欢使用 React 的 10 个原因。

React 仅是一个视图库

单页应用程序(SPA)遵循基于组件的用户界面的常识。组件获取输入并返回组件的实例作为输出。例如,输出可以是简单的按钮元素。你只需要为你的组件定义一次输入输出和内部行为,然后就能在任何 DOM 层次中随意地使用它来创建实例了。在最佳情况下,定义的组件易于重用并容易组装到其他组件中。

React 是基于组件的用户界面的理想选择。它只是一个视图库,并解决了所有已描述的组件的要求。它是一个致力于仅解决一个问题的库:提供了所有用于构建一个基于组件的用户界面的工具。

你可以看到 React 是作为 SPA 的一个组成部分。一旦你需要解决其他问题,你需要其他构建块。您的应用程序需要路由?可以看看适合 React 的路由解决方案。您的应用程序需要可扩展状态管理?可以看看不同状态管理器的解决方案。您需要执行异步请求吗?可以看看像 fetchaxios 或 superagent 的解决方案。

不过只用 React 也可以构建应用程序。它可能没有应用程序所需的成熟的路由和复杂的状态管理,但是它用于小应用程序没有问题。在 React 学习之路通过构建这样的应用程序来介绍了 React。

React 本身只是应用程序的一个构建块,它提供了基于组件的用户界面解决方案。像其它的构建块一样,它是可替换的。基于用户界面,你可以使用另一个解决方案来构建组件,它仍然可以和与其它构建块结合。

从这一点来看 Angular 是不同的。它不是一个库,而是一个框架。它提供了不止一个构建块。它是更刚性的解决方案。ReactJs 生态系统及其所有构建块放在一起也可以看作是一个框架。但是与 AngularJs 相比,React 的构建块是可替换的。而 Angular 帮你做好每件事。这看起来有些矛盾,一方面它应该很容易学,因为是使用自己的构建块,但另一方面,同时学习每一个构建块却相当困难。在 React 中想一次学很多东西也不容易。

React 是一个创新的地方

React 只是生态系统的核心,它周围所有的东西都是由构建块组成。你可以灵活地选择构建块去解决不同的问题。但是 React 依然保持着他们之间简单交换风格。他们之间简单的交换风格,让各种新奇的方法得以萌生。你可以使用 Redux 和 MobX 作为状态管理的示例。Redux 在早期就已经拥有了很强劲的势头,那时,MobX 还是一个小小社区的倡导者,他可以让那两种解决方案相互交换。

即使交互是 React 的核心建筑块。最近,像 Inferno 和 Preact 这样的库也开始和 React 竞争,他们可以用来代替 React。在 Augular 中使用这些方法是没有任何意义的,因为 Augular 有它自己的解决方式。

在 React 中可交换构建块,这使得尝试新方法成为可能。它的每个方法都给社区留了适应的空间,这使得 React 生态系统不断创新。

JSX - 混合了 HTML 和 JavaScript

React 有一套称为 JSX 的语法,用来制作组件。JSX 混合了 HTML 和 JavaScript。此外人们经常会在元素中使用内联样式,即混入 CSS。一开始可能让人觉得混淆,但终归会适应。你可以使用 JavaScript 组合和操作 DOM,但是它嵌入在 HTML 中。你可以使用内置的 JavaScript 功能,比如 map 和 filter 来显示多个(过滤后的)DOM 节点。你还可以使用三元操作来按条件进行渲染。你可以在 HTML 中使用完整的 JavaScript 功能。

在 SPA 解决方案中,它是一个新奇的方法,通过混合 HTML 和 JavaScript 来定义组件。其实这种方法在很早的服务端渲染方案(比如 JSP)中就已经存在了。

与之相反,Angular 清楚地区分了逻辑和视图的概念。它可以在 HTML 中使用内置的表达式,像 ng-repeat(Angular 1.x)或 ngFor(Angular 2)。这在 JSX 中会使用原生 JavaScript 的 map() 来完成。

React 的 API 很简单

React 是一个视图库。它只解决一个问题并把这个问题处理好。因此需要学习和理解的方法会很少。

React 组件使用生命周期方法。在 React 的 ES6 类组件中,你可以使用生命周期方法进入到组件生命周期。通常只需要写 render() 这个生命周期方法,它把元素作为组件的新实例来进行渲染。渲染的代码块会在组件初始化和每次组件更新时运行。这就够了。不过你可以使用多个生命周期方法来添加高级的组件行为。比如,你可以使用 constructor() 来初始化有状态的组件并添加类方法来操作状态。每次状态发生改变生命周期方法都会再次运行以更新视图。

组件的生命周期方法一共只有 9 个。多数情况下,你只会用到其中一半 - 哪怕是在成熟的 React 应用程序中。

然后你还需要知道两个 React ES6 类组件的方法:setState() 和 forceUpdate()。你一般不会用到后一个方法,它用于通过编程来强制更新一个组件。不过 setState() 通常用于更新组件的内部状态,这些状态是在 constructor() 生命期函数中初始化的。想像一下,你的列表组件中有一系列的项。然后你想从列表中添加或删除元素。你可以使用把列表保存在组件的内部状态 this.state 中,再通过 setState() 更新列表。

在 React 的官方文档 中你可以深入产了解 React 组件 API。

现在你已经知道了所有基本的组件方法。React 中还有其它一些概念,比如 props 和 state、children 属性或不同的组件申明。你可以慢慢来,一步一步地学完它们。

总之 React 本身没有陡峭的学习曲线。它只是一个需要掌握少量方法的视图层。如果你首先学习的 React,我建议只学习 React,不要再学其它的。《React 学习之路》就是这种学习思想,它涵盖了所有上面提到的你需要学习并掌握 React 的主题。

轻量级组件 => 最佳实践

React 中的组件有两个定义方式:ES6 类组件和函数形式的无状态组件。后者只是一些函数,接收参数输入并返回输出一个元素——这也是组件,但是它们不需要模板,只需要定义普通的 JavaScript 函数。我不能说 Angular 定义组件更容易。

function Button({ onClick, children }) {
    return (
        <button onClick={onClick} type="button ">
            {children}
        </button>
    );
}

随处使用函数式的无状态组件是个非常好的实践,但只在不需要组件状态和生命周期方法的时候才能这样做。这个最佳实践使你可以定义轻量级的小组件,却不失重用性、组件化和功能性,并且不会带来副作用。这样的最佳实践已经体现在上面的样板代码中。

单向数据流

与 Angular 1.x 不同,React 没有双向数据绑定。Angular 组件中的状态管理最终变得混乱不堪。状态几乎不能预测,也没有比较好的做法来处理它。在 Angular 1.x 中消除循环更新是件困难的事情。

React 使用单向数据流规则。组件使用 setState() 来显式更新内部状态。它必须从组件的状态对象 (this.state) 中获取状态,然后组件按更新后的状态再次渲染。对于组件的输入 (props),也会发生同样的事情,如果输入更新了,组件会通过其生命期方法 render 来更新。千万不要直接修改输入 (props) 或组件内部状态 (state)。应该遵循单向数据流规则,使 React 的状态管理更容易预测。