英文:Harry Wolff,翻译:前端大全 / v2li前端
本文是我上一篇《Vue 在哪些方面比 React 作得更好?》的后续。react
和上一篇不一样,本文的重点不是讲 Vue.js 作得比 React 好的方面,而是聊聊我不喜欢 Vue.js 的地方。浏览器
让咱们来研究一下我认为 React 比 Vue.js 作得更好的地方吧。框架
引言:我尽可能能客观地来表述,可是您确定会感觉到个人一些主观立场,毕竟,在过去 5 年中,我在专职用 React,显然,它是我在 UI 框架中的首选。ide
模板
Vue.js 最大的一个特色(坦率地说,Vue.js 最大的优点)就是其编写 UI 的模板语法。函数
在使用 React 5 年以后(尽量接近原生 JavaScript),我并不想费心去学习另外一种模板语法。工具
在个人职业生涯中,我曾学过各类语法,好比:Mustache.js、Handlebars、Lodash、Django 甚至更多。我不想由于要使用 Vue.js 而必须去学习另外一种模板语法。学习
虽然每种模板语法都有一些类似之处,但它们各自的特色让我在从一种切换到另外一种的过程当中很是头痛。翻译
另外一件我不喜欢的关于模板语法的事情是,它会在你编写的内容和在浏览器中运行的内容之间添加一层抽象。设计
React 中,会经过 JSX 编译为函数调用:
// React in <div title="Hello">Message: {message}</div>; // React out React.createElement(div, { title: 'Hello' }, 'Message: ' + message);
而在 Vue.js 中,我不知道模板将会编译成什么样。
React 和 Vue.js 在它们的模板中都仅容许使用 JavaScript 表达式,考虑到 JavaScript 的限制,我能够理解这点。可是 Vue.js 让我感到困惑的地方是它只能访问全局中的一部份内容。我知道这种限制确定事出有因,可是我真的不肯意在开发的时候时刻想着 Vue.js 模板不是简单封装了一层 JavaScript。
指令
指令是 Vue.js 的杀手级功能。它让 Vue.js 的模板变得特别强大。
可是。
指令其实是一种 API,您必须学习它们才能更有效地使用 Vue.js 模板。虽然与 Angular.js(我之前使用的方式)相比,Vue.js 指令少了不少,但这仍是会提升你的使用成本。
而 Vue.js 赋予指令的灵活性则进一步加重了这种状况,它带来了更多额外的学习成本。
好比指令参数,它有动态参数 而后还有指令修饰符(虽然我在第一篇文章中把它做为 Vue.js 的优势,但这也带来了额外的学习成本)!
指令的大多数语法都不可怕,可是我确实发现 v-for 指令 的语法很是反 JavaScript。它比其余任何东西都更接近 Python,这出如今 JavaScript 框架中会很奇怪。
组件
这点有点吹毛求疵了,但它能够佐证我对模板的观点。
因为 Vue.js 在很大程度上是模板驱动的框架,所以当您使用自定义组件扩展它时,您须要向 Vue.js 模板编译器告知所使用的组件。
这致使了不少重复的代码,在我看来彷佛彻底是多余的。
// Import your components as you normally would with ES Modules import ComponentA from './ComponentA'; import ComponentC from './ComponentC'; export default { components: { // Register them with the template compiler ComponentA, ComponentC, }, // Then finally use them in your template template: ` <ComponentA /> `, };
自定义事件
除了模板以外,自定义事件也是 Vue.js 和 React 的一个很大的区别。
React 中的全部内容都是组件和 props(到了一种很不健康的地步)。当您但愿子组件与父组件进行通讯时,您能够传递一个函数让子组件调用:
function Parent() { const onClick = () => alert('hello!'); return <Child onClick={onClick} />; } function Child({ onClick }) { return <button onClick={onClick}>Click me!</button>; }
而在 Vue.js 中则经过事件来进行父子组件通讯:
const ParentComponent = { components: { ChildComponent }, template: `<ChildComponent @greeting="alert('hello')" />`, }; const ChildComponent = { emits: ['greeting'], template: `<button @click="$emit('greeting')">Click me!</button>`, };
老实说,我不太肯定我对经过事件进行父子组件通讯的见解。
因为对发出和监听什么事件没有具体的约定,在 Angular.js 中使用这种方法会十分糟糕。
可是,Vue.js 经过工具解决了这个问题,当父级尝试监听某个事件时,组件实际上会发出这个事件。
若是不使用这个工具,我认为 Vue.js 可能会遇到与 Angular.js 相同的问题,可是 Vue.js 的工具确实很出色。
话虽如此,React 经过 props 传递函数的方式也不错,而且我的认为它更强大。
事件处理方法
与自定义事件相关的是 Vue.js 如何为其模板添加事件处理器。这也是我最鄙视的机制之一:引用字符串!
当在 Vue.js 模板中引用一个方法时,须要经过字符串的形式传递函数名称:
<button @click="greet">Greet</button>
嗯…过去我在使用字符串引用的时候一直很糟。
可是像上面同样,Vue.js 会经过工具捕获任何愚蠢的错别字。惋惜,这已是我很是不喜欢的一种方式了,而且不但愿再次使用它。
响应式
Vue.js 的大部分魔力来自其响应式。它让 Vue.js 可以在数据改变时有效且快速地更新 UI。它使我想起了 MobX,但在 Vue.js 中它是专为 Vue.js 设计的而且内置其中。
可是,MobX 和 Vue.js 的响应式都有权衡取舍,在组件中使用响应式时,您必须考虑其实现细节。
例如,当建立响应式对象时,您经过reactive 函数包装对象。可是,当您想使用原始值时,须要将其包装在 ref 中,其做用与 React 的 useRef 的 hook 很是类似。
基于 Vue.js 的响应式原理(使用 Proxy),因此当要破坏一个 reactive 对象时,则须要将其包装在 toRefs(reactiveObject)中,以确保您不会丢失反应性绑定。
对于原始参考值,Vue.js 会自动解开模板中的参考值,这点虽然很好,但会形成引用值不一致的问题。
在模板中,您没必要解包,可是在组件 JavaScript 中,您须要解包。对我而言,这些上下文切换彷佛是没必要要的并且乍一看会形成混乱。
对于常见的用例,确实不多会遇到这些边缘状况,可是我很关注它的扩展性。
这与 React 几乎都是简单应用 useState 和 useRef 相反,后者会返回 setter 函数和一致的 ref-object 接口。也许 React 的 API 太简单了,所以它将大多数操做推给了最终开发者。但这也是我如今最关心的,就是里边不要有什么奇淫巧计。
尾声
与 Vue.js 相比,我更喜欢 React 的哲学。
我不喜欢 Vue.js 替我作了太多事情。我更喜欢使用原始的函数和方法来彻底控制个人 UI(React 就是这样的)。
React 并不是没有怪异模式,但至少 React 的怪异点我是清楚的。我写的东西和 React 作的事情之间几乎没有间接层。(忽略 react-reconciler 库的黑暗魔力,祝那些尝试深层次调试这些堆栈的人好运吧)。
很难说 React 更好,由于我我的确实更偏心 React!若是 Vue.js 更合你意,请继续使用 Vue.js!我惟一想作的就是强调 Vue.js 和 React 之间的区别,以及为何React 还是我 UI 库的首选。