用了 5 年 React,我不喜欢 Vue.js 的地方有这些
(给前端大全加星标,提升前端技能)
英文:Harry Wolff,翻译:前端大全 / v2li
本文是我上一篇《Vue 在哪些方面比 React 做得更好?》的后续。
和上一篇不同,本文的重点不是讲 Vue.js 做得比 React 好的方面,而是聊聊我不喜欢 Vue.js 的地方。
让我们来研究一下我认为 React 比 Vue.js 做得更好的地方吧。
引言:我尽量能客观地来表述,但是您肯定会感受到我的一些主观立场,毕竟,在过去 5 年中,我在专职用 React,显然,它是我在 UI 框架中的首选。
模板
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 库的首选。
- EOF -
觉得本文对你有帮助?请分享给更多人
推荐关注「前端大全」,提升前端技能
点赞和在看就是最大的支持❤️