在实际示例中比较React和Vue

该材料的作者(我们今天出版的翻译版)说,他必须在工作中使用Vue,并且他已经很好地研究了这个框架。 但是,他总是很想知道事物在其他世界(即React宇宙)中的状况。

他阅读了文档,观看了一些培训视频,尽管这一切对他来说都非常有用,但他还是想真正了解React和Vue之间的区别。 对他来说,寻找框架之间的差异并不是要找出它们是否支持文档的虚拟对象模型,或者它们如何呈现页面。 他希望有人向他解释代码的功能,以显示其中发生了什么。 他希望找到一篇专门致力于发现这种差异的文章,并读到仅了解Vue或React的人(或Web开发领域的一个全新人员)可以更好地理解这些框架之间的差异。



但是,他找不到这样的文章。 这一事实使他认识到,他本人需要撰写这样的文章并一路撰写,了解React和Vue之间的异同。 实际上,这是他在比较这两个框架时所做的实验的描述。

一般规定



Vue还是React?

对于实验,我决定创建几个相当标准的待办事项应用程序,以使用户可以将项目添加到待办事项列表中并将其从中删除。 这两个应用程序都是使用标准的create-react-app (针对React的create-react-app和针对Vue的vue-cli )开发的。 如果没有人知道,CLI是命令行界面(Command Line Interface)的缩写,即命令行界面。

现在,我建议在这里查看有问题的应用程序的外观。


Vue和React创建的应用程序

以下是包含这些应用程序代码的存储库: Vue ToDoReact ToDo

到处都使用相同的CSS代码,唯一的区别是相应文件的位置完全相同。 鉴于此,让我们看一下项目的结构。


使用Vue和React的项目结构

如您所见,这两个项目的结构几乎相同。 唯一的主要区别是React应用程序具有三个CSS文件,而Vue应用程序根本没有它们。 原因是,当使用create-react-app ,React组件随附了随附的CSS文件,并且在特定组件文件中声明样式时,Vue CLI使用了不同的方法。

结果,一种方法和另一种方法都使我们可以实现相同的目标,而如果需要,没有什么可以阻止我们组织与Vue或React不同的样式。 实际上,这全都取决于创建Web项目的人的个人喜好。 例如,CSS构造主题在开发人员社区中不断被讨论。 现在,我们仅遵循所讨论框架的CLI中规定的标准CSS方法。

但是,在进一步介绍之前,让我们看一下典型的Vue和React组件的外观。

这是Vue组件代码(在我们的项目中,它在ToDoItem.vue文件中)。

 <template>   <div class="ToDoItem">       <p class="ToDoItem-Text">{{todo.text}}</p>       <div class="ToDoItem-Delete"            @click="deleteItem(todo)">-       </div>   </div> </template> <script>   export default {       name: "to-do-item",       props: ['todo'],       methods: {           deleteItem(todo) {               this.$emit('delete', todo)           }       }   } </script> <style>   .ToDoItem {       display: flex;       justify-content: center;       align-items: center;   }   .ToDoItem-Text {       width: 90%;       background-color: white;       border: 1px solid lightgrey;       box-shadow: 1px 1px 1px lightgrey;       padding: 12px;       margin-right: 10px;   }   .ToDoItem-Delete {       width: 20px;       padding: 5px;       height: 20px;       cursor: pointer;       background: #ff7373;       border-radius: 10px;       box-shadow: 1px 1px 1px #c70202;       color: white;       font-size: 18px;       margin-right: 5px;   }   .ToDoItem-Delete:hover {       box-shadow: none;       margin-top: 1px;       margin-left: 1px;   } </style> 

这是React组件的代码( ToDoItem.js文件)。

 import React, {Component} from 'react'; import './ToDoItem.css'; class ToDoItem extends Component {   render() {       return (           <div className="ToDoItem">               <p className="ToDoItem-Text">{this.props.item}</p>               <div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div>           </div>       );   } } export default ToDoItem; 

现在是时候深入研究细节了。

数据修改如何完成?


更改数据也称为“数据突变”。 我们正在谈论对应用程序存储的数据所做的更改。 因此,如果我们需要将某个人的名字从“约翰”更改为“马克”,那么我们所说的是“数据突变”。 React和Vue之间的关键区别在于数据更改方法。 即,Vue创建一个data对象,数据位于其中,并且其内容可以自由更改。 React创建了一个state对象,该state对象存储了应用程序的状态,在使用该对象时,需要付出额外的努力来更改数据。 但是,在React中,由于某种原因,所有内容的排列方式都是有原因的,下面我们将进行讨论,并且首先,我们将考虑上述对象。

这就是Vue使用的data对象的样子。

 data() {     return {         list: [             {               todo: 'clean the house'             },             {               todo: 'buy milk'             }         ],     } }, 

这是React中使用的state对象的样子:

 constructor(props) {       super(props);       this.state = {           list: [               {                   'todo': 'clean the house'               },               {                   'todo': 'buy milk'               }           ],       };   }; 

如您所见,在两种情况下,我们描述的都是相同的数据,但它们的设计不同。 结果,可以说初始数据到Vue和React中组件的传输看起来非常相似。 但是,正如已经提到的,在这些框架中更改现有数据的方法有所不同。

假设我们有一个像name: 'Sunil'这样的数据元素name: 'Sunil' 。 然后我给name属性分配了自己的名字。

在Vue中,您可以使用this.name构造访问此数据。 这是如何更改它们: this.name = 'John' 。 我真的不知道自己的名字真的改变了会怎样,但是在Vue中它就是这样。

在React中,您可以使用this.state.name构造访问相同的数据。 但是通过编写类似this.state.name = 'John'东西来改变它们是不可能的,因为React有防止这种数据改变的限制。 因此,在React中,您必须使用this.setState({name: 'John'})

这种操作的结果与在Vue中执行更简单的操作后获得的结果相同。 您必须在React中编写更多的代码,但是在Vue中,有一些类似于setState函数的特殊版本的东西,它似乎是在简单的数据更改时被调用的。 因此,总而言之,React需要将setState与需要更改的数据一起使用,Vue假设开发人员希望通过更改data对象内部的data来使用类似的东西。

现在,让我们自问为什么setState了React以及为什么根本需要setState函数。 您可以从Revant Kumar中找到这些问题的答案:“这是因为React会根据状态变化重新执行某些生命周期挂钩,例如componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 。 当您调用setState函数时,它将了解状态已更改。 如果要直接更改状态,React将不得不做更多的工作来跟踪更改,确定要运行的生命周期挂钩等等。 结果,React使用setState使生活setState 。”

现在,我们已经弄清了数据更改,下面我们来讨论一下如何在两个版本的应用程序中将新项目添加到待办事项列表中。

将新项目添加到待办事项列表


▍反应


这是在React中做的方法。

 createNewToDoItem = () => {   this.setState( ({ list, todo }) => ({     list: [         ...list,       {         todo       }     ],     todo: ''   }) ); }; 

在此,用于数据inputinput )的字段具有属性value 。 该属性通过使用一对相互连接的函数自动更新,这些函数形成了所谓的双向数据绑定(如果您之前从未听说过-请稍等,我们将在向Vue应用程序添加元素的部分中对此进行讨论)。 由于存在附加到input字段的附加onChange事件onChange器,因此我们创建了这种双向通信。 让我们看一下该字段的代码,以便您可以了解此处发生的情况。

 <input type="text"      value={this.state.todo}      onChange={this.handleInput}/> 

input字段的值更改时,将调用handleInput函数。 通过将其设置为input字段中的值,可以更新state对象内的todo元素。 这就是handleInput函数的外观。

 handleInput = e => { this.setState({   todo: e.target.value }); }; 

现在,当用户单击应用程序页面上的+按钮以将新记录添加到列表中时, createNewToDoItem函数将调用this.setState方法并将其传递给函数。 该函数有两个参数。 第一个是state对象的整个list数组,第二个是由handleInput函数更新的todo元素。 然后,该函数返回一个包含旧list数组的新对象,并在该数组的末尾添加一个新的todo元素。 列表的工作是使用spread运算符组织的(如果您以前从未遇到过,请注意,这是ES6的新功能之一,请查找有关它的详细信息)。

最后,将一个空字符串写入todo ,它会自动更新input字段中的value

ueVue


以下构造用于将新项目添加到Vue中的待办事项列表。

 createNewToDoItem() {   this.list.push(       {           'todo': this.todo       }   );   this.todo = ''; } 

在Vue中,输入字段具有v-model指令。 它允许您组织双向数据绑定。 看一下该字段的代码,并讨论这里发生的事情。

 <input type="text" v-model="todo"/> 

v-model指令将字段绑定到存在于名为toDoItem的数据对象中的toDoItem 。 页面加载后,在toDoItem写入了空行,看起来像todo: '' toDoItem

如果已经有一些数据,如todo: 'add some text here' ,则相同的文本将进入输入字段,即- 'add some text here' 。 无论如何,如果我们返回带有空字符串的示例,由于数据绑定,我们在字段中输入的文本将落入todo属性中。 这是双向的数据绑定,也就是说,在字段中输入新数据会导致在data对象中记录此数据,而在对象中更新数据会导致该数据在字段中出现。

现在,请记住我们上面讨论的createNewToDoItem()函数。 如您所见,我们将todo的内容放入list数组,然后将一个空字符串写入todo

从列表中删除项目


▍反应


在React中,该操作是这样执行的。

 deleteItem = indexToDelete => {   this.setState(({ list }) => ({     list: list.filter((toDo, index) => index !== indexToDelete)   })); }; 

deleteItem函数位于ToDo.js文件中时,您可以从ToDoItem.js访问它,首先将该函数作为属性传递给<ToDoItem/> 。 看起来是这样的:

 <ToDoItem deleteItem={this.deleteItem.bind(this, key)}/> 

在这里,我们首先传递该函数,该函数可用于子组件。 此外,我们将其绑定并传递key参数。 函数使用此参数来区分要删除的ToDoItem元素和其他元素。 然后,在ToDoItem组件内部,执行以下操作。

 <div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div> 

要访问位于父组件中的功能,需要做的就是使用this.props.deleteItem构造。

ueVue


这样删除Vue中的列表项即可。

 onDeleteItem(todo){ this.list = this.list.filter(item => item !== todo); } 

Vue要求的元素删除方法与我们在React中使用的方法略有不同。 即,要采取三个步骤。

首先,这是您需要在需要调用该函数以将其删除的元素中执行的操作。

 <div class="ToDoItem-Delete" @click="deleteItem(todo)">-</div> 

然后,您需要在子组件(在本例中为ToDoItem.vue )中创建方法作为方法的emit函数,如下所示。

 deleteItem(todo) {   this.$emit('delete', todo) } 

此外,您可能会注意到我们正在ToDoItem.vue内向ToDo.vue添加ToDoItem.vue

 <ToDoItem v-for="todo in list"         :todo="todo"         @delete="onDeleteItem" // <-- this :)         :key="todo.id" /> 

这就是所谓的自定义事件侦听器。 它响应以deleteemit呼叫。 如果捕获到类似事件,则会调用onDeleteItem函数。 它位于ToDo.vue内部,而不位于ToDoItem.vue 。 如上所述,此函数仅过滤位于data对象中的todo数组,以删除在其上单击的元素。

另外,值得注意的是,在使用Vue的示例中,可以简单地在@click编写与emit函数相关的代码。 它可能看起来像这样。

 <div class="ToDoItem-Delete" @click="$emit('delete', todo)">-</div> 

这样可以将删除列表项所需的步骤数从三个减少到两个。 如何进行取决于开发人员的偏好。

总结这一节,我们可以说在React中,通过this.props组织对父组件中描述的功能的访问(假设将this.props传递给子组件,这是一种标准技术,可以在任何地方找到)。 在Vue中,子组件必须使用emit函数触发事件,并且这些事件已由父组件处理。

与事件监听器一起使用


▍反应


在React中,简单事件(例如click事件)的事件侦听器非常简单。 这是为创建新的待办事项的按钮创建click事件处理程序的示例。

 <div className="ToDo-Add" onClick={this.createNewToDoItem}>+</div> 

这里的一切安排都非常简单,这与使用纯JavaScript处理此类事件非常相似。

应该注意的是,在这里设置事件监听器以按下按键(例如Enter比在Vue中花费更长的时间。 在这里,您需要按以下onKeyPress处理onKeyPress事件。 这是输入字段的代码。

 <input type="text" onKeyPress={this.handleKeyPress}/> 

handleKeyPress函数识别createNewToDoItem Enter时,将调用createNewToDoItem函数。 看起来像这样。

 handleKeyPress = (e) => { if (e.key === 'Enter') { this.createNewToDoItem(); } }; 

ueVue


Vue中的事件处理程序非常易于配置。 只需使用@符号,然后指定我们要使用的侦听器类型即可。

例如,要添加单击事件侦听器,可以使用以下代码。

 <div class="ToDo-Add" @click="createNewToDoItem()">+</div> 

请注意, @clickv-on:click缩写v-on:click 。 Vue事件侦听器擅长于非常精细地控制。 例如,将.once构造附加到侦听器将导致侦听器仅触发一次。

有许多缩写可以简化对键盘上的击键做出响应的侦听器的编写。 如前所述,在React中,这比在Vue中花费的时间更长。 在这里,这非常简单。

 <input type="text" v-on:keyup.enter="createNewToDoItem"/> 

将数据传递给子组件


▍反应


在React中,属性在创建时会传递给子组件。 例如,像这样:

 <ToDoItem key={key} item={todo} /> 

在这里,您可以看到两个传递给ToDoItem组件的属性。 从现在开始,可以通过this.props在子组件中访问它们。

例如,要访问item.todo属性,只需使用this.props.item构造。

ueVue


在Vue中,属性在创建时也会传递给子组件。

 <ToDoItem v-for="todo in list"           :todo="todo"           :key="todo.id"           @delete="onDeleteItem" /> 

之后,将它们传递给子组件的props数组,例如,使用props: [ 'todo' ]构造。 您可以按名称访问子组件中的这些属性,在本例中为'todo'名称。

将数据传递到父组件


▍反应


在React中,函数首先作为调用子组件的属性传递给子组件。 然后计划调用此函数,例如,通过将其添加为onClick处理程序,或通过调用this.props.whateverTheFunctionIsCalled进行调用。 这导致调用位于父组件中的函数。 有关从列表中删除项目的部分介绍了此过程。

ueVue


使用Vue时,在子组件中编写一个将数据传递到父函数的函数就足够了。 在父组件中编写了一个侦听值传递事件的函数。 当发生类似事件时,将调用此类函数。 与React一样,可以在关于从列表中删除项目的部分中找到此过程的描述。

总结


我们讨论了如何在基于Vue和React的应用程序中添加,删除和修改数据,如何以属性形式从父组件向子组件传输数据,以及如何从子组件向父组件发送数据。 我们相信,在分析了相似性和差异性的示例之后,Vue和React可以用肉眼看到。

当然,React和Vue之间还有许多其他小的区别,但是我希望我们在这里介绍的内容将成为理解这些框架如何工作的良好基础。 在为新项目选择合适的平台时,通常会分析框架。 我们希望这些材料将有助于做出这样的选择。

亲爱的读者们! 您认为,React和Vue之间有哪些最重要的差异会影响对特定框架的选择,例如,将其作为某个项目的基础?

Source: https://habr.com/ru/post/zh-CN419373/


All Articles