欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React,迁移到Vue的心路历程

程序员文章站 2022-03-04 12:15:33
react,迁移到 vue 的心路历程 前几年我一直在使用 react。最初仅有 react,后来使用 redux 和 react 的其他库(react-router、react-redux、pro...

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 的思想而来(https://redux.js.org/faq/immutable-data#why-is-immutability-required-by-redux),而且尽管 react 本身能处理可改变的数据,但在 react 中的推荐做法是不要修改 props 或 state 的数据(https://reactjs.org/docs/optimizing-performance.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(https://vuex.vuejs.org/en/mutations.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 时发现的一些最重要的问题。这并不是一篇严谨的比较,不能作为选择库的依据。但如果你也像我一样不得不从一个库切换到另一个库,或者只是想了解更多的关于两个库的信息,这篇文章也许会有帮助。