三年 React 开发经验的我,迁移到 Vue 的心路历程

mjzhang 2018-07-23

三年 React 开发经验的我,迁移到 Vue 的心路历程

三年 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 开发经验的我,迁移到 Vue 的心路历程

React 和 Angular 相似的地方

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

<div id="app-3">

<span v-if="seen">Now you see me</span>

<ol>

<todo-item

v-for="item in groceryList"

v-bind:todo="item"

v-bind:key="item.id">

</todo-item>

</ol>

<button v-on:click="reverseMessage">Reverse Message</button>

</div>

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

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

三年 React 开发经验的我,迁移到 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 与组件交互的方式有一些区别,下面我来介绍下这些区别。

三年 React 开发经验的我,迁移到 Vue 的心路历程

Dispatch 和 Commit

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

三年 React 开发经验的我,迁移到 Vue 的心路历程

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

import { ADD_TODO, REMOVE_TODO } from '../actionTypes'

function addTodo(text) {

return {

type: ADD_TODO,

text

}

}

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

三年 React 开发经验的我,迁移到 Vue 的心路历程

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

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

三年 React 开发经验的我,迁移到 Vue 的心路历程

从 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 组件中访问,非常简单:

const Counter = {

template: `<div>{{ count }}</div>`,

computed: {

count () {

return this.$store.state.count

}

}

}

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

<template>

<div>

<todo-item :todo="todo"></todo-item>

</div>

</template>

<script>

import TodoItem from './TodoItem.vue'

export default {

components: {

TodoItem

},

data () {

return {

todo: {

text: 'Learn Vue',

isComplete: false

}

}

}

}

</script>

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

class TodoList extends React.Component {

render() {

<div>

<TodoItem todo={this.props.todo} />

</div>

}

}

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

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

三年 React 开发经验的我,迁移到 Vue 的心路历程

结论

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

总结一下重点:

  • Vue 默认不包含 JSX,很强调脚本和模板分离;
  • Redux 和 Vuex 背后的数据流思想很相似;
  • Redux 十分依赖于 state 的不可改变性,而 Vuex 不关心 state 是否不可改变;
  • Vue 允许 dispatch,也允许直接从组件中 commit,但最好还是严格些,只允许 dispatch 会比较好;
  • 任何 Vue 组件都可以直接访问 store。

原文:https://medium.com/@omm2/doing-vue-after-three-years-with-react-3d36d53abbd6

作者:Anya Pavlova,unu GmbH的软件工程师。

译者:弯月,责编:屠敏

“征稿啦!”

CSDN 公众号秉持着「与千万技术人共成长」理念,不仅以「极客头条」、「畅言」栏目在第一时间以技术人的独特视角描述技术人关心的行业焦点事件,更有「技术头条」专栏,深度解读行业内的热门技术与场景应用,让所有的开发者紧跟技术潮流,保持警醒的技术嗅觉,对行业趋势、技术有更为全面的认知。

如果你有优质的文章,或是行业热点事件、技术趋势的真知灼见,或是深度的应用实践、场景方案等的新见解,欢迎联系 CSDN 投稿,联系方式:微信(guorui_1118,请备注投稿+姓名+公司职位),邮箱([email protected])。

相关推荐