用户登录
用户注册

分享至

React,迁移到Vue的心路历程

  • 作者: 过去的已过去再也回不去的过去
  • 来源: 51数据库
  • 2021-09-21

react,迁移到 vue 的心路历程

前几年我一直在使用 react。最初仅有 react,后来使用 redux 和 react 的其他库(react-router、react-redux、prop-types 等)配合使用。我喜欢 react 的简单和方便,使用 react 的时光一直都很快乐。我喜欢这个时代,有太多的好工具帮助我们更快更好地开发应用。

近三个月我在用 vue 构建 web 应用,在此我想分享一些我作为一名 react 拥护者的 vue 使用经验。我不想写成一篇 vue/react 比较的文章,这种文章太多了,包括官方的 vue 文档(https://vuejs.org/v2/guide/comparison.html)。它只是一些关于切换库的个人观点。

如果你使用过 vue 和 react,或者像我一样刚刚从 react 切换到 vue 正在适应,或者只是想多一些了解,我希望这篇文章能对你有帮助。

react 和 angular 相似的地方

相比 react,vue 有时更多地被拿来和 angular 比较。实际上,浏览 vue 模板时我们首先看到的就是双向绑定和 directive,与 angular 非常类似:

nowyouseeme

reversemessage

尽管 vue 支持 jsx,但通常的方法还是将模板和 javascript 分开。虽然react jsx 的语法很像原生语法,并且反映了通常的 javascript 语法,但 vue 的模板语法非常高级,它包含 directive、快捷方式和条件渲染,使得 vue 更像 angular。不过,相似性也就到此为止了。

当然,前后端使用同一种模板可能会有很大好处(比如 node.js/pug + vue/pug),而且尽管 vue 提供的众多 directive 可能很有用,但对于我来说,从 react 的 jsx 切换到 vue 的模板依然很痛苦。

redux vs. vuex

在应用中,react 通常会与某种数据流库结合使用,最流行的就是 redux。vue 也有个类似的数据流库,叫做 vuex,我很高兴地发现它和 redux 非常相似。实际上,从 redux 切换到 vuex 没有任何痛苦,因为与 react 跟 vue 相比,这两个库有更多的共同点。

主要的区别就是 redux 严重依赖于状态的不可修改性。原因就是 redux 从 react 的思想而来(http://www.51sjk.com/Upload/Articles/1/0/298/298639_20210728145213074.jpg react 本身能处理可改变的数据,但在 react 中的推荐做法是不要修改 props 或 state 的数据(http://www.all.com/files/Articles/416/0/222/222644_20210701214520040.html#the-power-of-not-mutating-data),以便 react 获得最好的效率。

在 react 中, state 的变化会触发该组件以下的整个组件子树的重新渲染。为了避免不必要的子组件重新渲染, 我们需要使用 purecomponent,或尽量实现 shouldcomponentupdate。还需要使用不可变的数据结构让 state 的变化更容易被优化。(https://vuejs.org/v2/guide/comparison.html#optimization-efforts)

然而 vuex 完全不关心 state 是否不可修改。

在 vue 中,组件的依赖会自动在渲染过程中跟踪,因此当 state 发生变化时,可以精确地知道哪个组件需要渲染。(https://vuejs.org/v2/guide/comparison.html#optimization-efforts)

因此,react/vue 与组件交互的方式有一些区别,下面我来介绍下这些区别。

dispatch 和 commit

redux 中的数据流十分严格且直接。组件会 dispatch action,而 action 由 action 的创建器函数返回。然后 reducer 会根据收到的 action 返回新的 state。最后,组件会通过 store 监听 state 的变化,并在 connect() 函数的帮助下访问state中的属性。

每个 action 都会通过 action 创建器。尽管理论上来说可以直接从组件中 dispatch 一个 action,但通常不这样做。action 的语法本身就鼓励我们将 action 的逻辑封装在 action 创建器函数中,即使是最简单的 action:

import{add_todo,remove_todo}from'../actiontypes'

functionaddtodo(text){

return{

type:add_todo,

text

}

}

尽管 vuex 的数据流很相似,但它并不严格要求组件与 state 交互的方式。首先,组件可以 dispatch action。这通常是一些异步动作,比如从后台获取数据等。之后,action 会 commit 一个 mutation。mutation 函数与 reducer 的相似之处就是,它是唯一能够改变 state 的东西。但还有另一种方法:组件可以直接 commit 一个 mutation,有时候跳过 action 直接修改数据是很方便的 。

从组件 commit mutation 的行为不仅没有被严格禁止,vuex 的文档甚至鼓励在异步的情况下直接使用 action(http://www.all.com/files/Articles/416/0/222/222644_20210701214521127.html#committing-mutations-in-components)。由于我习惯了 react 的更严格的数据流,我更主张严格分离的概念——不管什么情况下,即使是同步或者非常简单的情况,commit mutation 也应该只能由 action 实施。

如果组件只能通过 action 来创建 mutation,那么组件和 mutation 之间就会有一个额外的层,保证组件和 mutation 之间的低耦合,最终使得代码更容易维护和修改。

从 store 中获取数据

为了与 react 组件内部的 store 交互,我们需要使用 connect() 函数。我认为 react/redux 最让人不爽的一点就是,你不得不判断哪些组件该用 connect(),哪些不该用。使用 connect() 的组件通常被称为容器,而不使用 connect() 的一般称为表现组件,或者“笨”组件。

但 connect() 不能用得太多,因为它的性能很差。但如果只在顶层组件使用的话,需要传递给下层组件的 props 就会迅速增多。这个问题曾多次被讨论(如这里https://redux.js.org/docs/faq/reactredux.html#react-multiple-components和这里https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0),但实际上,即使容器组件的数量还算合理,传递给下层的 props 也挺让人头疼的。

我很意外地返现,在 vue 中我根本不需要考虑这个问题。store 可以从任何 vue 组件中访问,非常简单:

constcounter={

template:`

{{count}}

`, computed:{ count(){ returnthis.$store.state.count } } }

也就是说,从一个组件传递给另一个组件的 props 数量非常少,而且只需要传递那些没有保存在 store 中的数据。不过,在 vue 中传递 props 的语法却非常不方便:

这里我们要给子组件(todoitem)传递 props,但却不能在子组件定义的位置传递,而必须在模板里传递。相比之下,react 中的 props 传递更加自然,是在子组件渲染时完成的:

classtodolistextendsreact.component{

render(){

} }

尽管在 vue 中传递 props 很不方便,但好处是,由于 store 能在任何组件中访问,实际需要传递的 props 比 react 中少得多,而在 react 中,即使有足够多的容器组件,平均每个组件收到的 props 数量也非常大。

更新:新的 react context api(https://reactjs.org/docs/context.html)提供了一种在组件树中直接访问数据而不需要在每层手动传递 props。

结论

如开头所说,本文只是一些我在从 react 迁移到 vue 时发现的一些最重要的问题。这并不是一篇严谨的比较,不能作为选择库的依据。但如果你也像我一样不得不从一个库切换到另一个库,或者只是想了解更多的关于两个库的信息,这篇文章也许会有帮助。

软件
前端设计
程序设计
Java相关