查看原文
其他

用了 5 年 React,我不喜欢 Vue.js 的地方有这些

The following article is from 前端大全 Author v2li

(给大前端技术之路加星标,提升前端技能

英文: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 -


觉得本文对你有帮助?请分享给更多人

关注「大前端技术之路」加星标,提升前端技能


点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存