当前位置: 首页 > 科技观察

比较在React和Vue中构建应用程序之间的区别

时间:2023-03-17 11:24:12 科技观察

React与Vue:现在使用ReactHooksVue3CompositionAPI!ReactvsVue:传奇还在继续几年前,我决定尝试在React和Vue中构建一个相当标准的ToDo应用程序。这两个应用程序都是使用默认CLI构建的(React的create-react-app和Vue的vue-cli)。我的目的是编写公正的内容,并概述如何使用这两种技术执行某些任务。当ReactHooks发布时,我在原始文章中附加了“2019版”,它用FunctionalHooks取代了ClassComponents的使用。随着Vue版本3及其组件API的发布,是时候用“2020版本”再次更新本文了。让我们快速看一下这两个应用程序的外观:两个应用程序的CSS代码完全相同,但它们的位置不同。考虑到这一点,让我们看一下这两个应用程序的文件结构:最终,它们都实现了相同的目标,没什么好说的,你不能继续在React或Vue中以不同的方式构建你的文件。这真的取决于个人喜好。你会从开发者社区听到很多关于CSS结构的讨论,尤其是React,因为有很多CSS-in-JS解决方案,比如styled-components和emotions。顺便说一下,CSS-in-JS的字面意思就是这个意思。虽然这些功能很有用,但到目前为止,我们只会遵循两个CLI中概述的结构。但在继续之前,让我们快速浏览一下典型的Vue和React组件是什么样的:我们如何改变数据?但首先,“变异数据”到底是什么意思?听起来有点技术性?基本上,它只是意味着改变我们存储的数据。因此,如果我们想将一个人的名字的值从John更改为Mark,我们将“改变数据”。所以,这就是React和Vue之间的关键区别所在。Vue本质上创建了一个可以自由更新数据的数据对象,而React通过状态挂钩来处理这个问题。让我们看看下面两张图片中的设置,我们将解释发生了什么:Reactstate:Vuestate:所以你可以看到我们向两者传递了相同的数据,但是结构有点不同。使用React,或者至少从2019年开始,我们通常通过一系列Hook来处理状态。如果您以前没有见过这样的概念,起初它们可能看起来有点奇怪。基本上,它是这样工作的:假设我们要创建一个待办事项列表。我们可能需要创建一个名为list的变量,它可以接受一个字符串或对象数组(例如,如果我们想给每个待办事项字符串一个ID和其他一些东西,我们可以通过编写const[list,setList]=useState([])。这里我们使用了React称之为Hook的东西——叫做useState。这基本上允许我们在我们的组件中保持本地状态。另外,你可能已经注意到我们在useState()内部使用它一个空数组[]被传入。我们放在那里的是我们希望列表初始设置的内容,在我们的例子中,是一个空数组。但是,正如您从上图中看到的那样,我们在数组内部传入一些数据,最终成为列表的初始化数据。想知道setList的作用吗?稍后会详细介绍!在Vue中,通常将组件的所有变量数据放在返回对象的setup()函数中包含要公开的数据和功能(这基本上意味着您希望能够在您的应用程序中使用的东西)。您会注意到应用程序中的每条状态数据(即我们希望能够改变的数据)都包含在ref()函数中。这个ref()函数是我们从Vue导入的,以允许我们的应用程序在这些数据发生更改或更新时进行更新。简而言之,如果您想在Vue中创建可变数据,请将变量分配给ref()函数并将任何默认数据放入其中。那么我们如何在应用程序中引用可变数据呢?好吧,假设我们有一些名为name的数据,它被赋予了Sunil的值。在React中,因为我们使用useState()创建较小的状态,所以我们很可能已经创建了一些类似const[name,setName]=useState('Sunil')的东西。在我们的应用程序中,我们将通过简单地调用名称来引用相同的数据。现在,这里的主要区别是我们不能简单地写name='John',因为React有适当的限制来防止发生这种简单的、任意的突变。所以,在React中,我们会写setName('John')。这是setName位发挥作用的地方。基本上,在const[name,setName]=useState('Sunil')中,它会创建两个变量,一个变量将是constname='Sunil',第二个constsetName被分配一个函数,函数可以重新创建名称新的。价值。在Vue中,它位于setup()函数内部,称为constname=ref('Sunil')。在我们的应用程序中,我们将通过调用name.value来引用它。使用Vue,如果我们想使用在ref()函数中创建的值,我们将在变量上查找.value而不是简单地调用变量。换句话说,如果我们想要保存状态的变量的值,我们将寻找name.value而不是name。如果你想更新name的值,你可以通过更新name.value来实现。例如,假设我想将我的名字从Sunil更改为John。我可以通过编写name.value="John"来做到这一点。我不确定被称为John是什么感觉,但是,嘿,它发生了!实际上,React和Vue在这里做着同样的事情,创建可以更新的数据。每当更新包含在ref()函数中的数据时,Vue基本上默认结合自己的name和setName版本。React要求您使用内部值调用setName()来更新状态,如果您尝试更新数据对象中的值,Vue会假设您这样做了。那么,为什么React还要将值和函数分开呢?为什么还要使用useState()?本质上,React希望能够在状态发生变化时重新运行某些生命周期挂钩。在我们的示例中,如果调用setName(),React将知道某些状态已更改,因此可以运行这些生命周期挂钩。如果你直接改变状态,React将不得不做更多的工作来跟踪变化和运行生命周期挂钩等。现在我们有了一些解决方法,让我们通过查看如何将新项目添加到两个“待办事项”来更详细地了解.我们如何创建新的待办事项?反应:constcreateNewToDoItem=()=>{constnewId=generateId();constnewToDo={id:newId,text:toDo};setList([...list,newToDo]);setToDo("");};React是如何制作的?在React中,我们的输入字段有一个名为value的属性。每次通过onChange事件侦听器更改其值时,该值都会自动更新。JSX(基本上是HTML的一种变体)看起来像这样:它更新状态。handleInput函数如下所示:constandleInput=(e)=>{setToDo(e.target.value);};现在,只要用户按下页面上的+按钮添加新项目,就会触发createNewToDoItem函数。让我们再看看这个函数,看看发生了什么:constcreateNewToDoItem=()=>{constnewId=generateId();constnewToDo={id:newId,text:toDo};setList([...list,newToDo]);setToDo("");};本质上,newId函数基本上是创建一个新的ID,该ID将提供给我们的新待办事项。newToDo变量是一个对象,其ID键的值为newId。它还有一个文本键,将toDo的值作为它的值。这与输入值更改时更新的toDo相同。然后我们用完setList函数并传入一个包含整个列表以及新创建的newToDo的数组。如果...列表位看起来很奇怪,开头的三个点称为展开运算符,它基本上将列表中的所有值作为单个项传递,而不是简单地将完整项作为数组传递。困惑?如果是这样,我强烈推荐阅读Scatter,因为它很棒!无论如何,最后我们运行setToDo()并传入一个空字符串。这样,我们的输入值为空,我们可以输入一个新的toDos。Vue:functioncreateNewToDoItem(){constnewId=generateId();list.value.push({id:newId,text:todo.value});todo.value="";}Vue是怎么做到的呢?在Vue中,输入字段上有一个名为v-model的句柄。这允许我们做一些叫做双向绑定的事情。让我们快速浏览一下输入字段并解释发生了什么:V-模型将此字段的输入与我们在setup()函数顶部创建的变量绑定,然后将其作为键公开给我们返回的对象。到目前为止,我们还没有介绍对象返回的内容,所以为了您的信息,这是我们从ToDo.vue中的setup()函数返回的内容:在这里,list、todo和showError是我们的有状态值,其他一切都是我们希望能够在应用程序的其他地方调用的函数。好的,从切线返回,当页面加载时,我们必须将todo设置为空字符串,例如:consttodo=ref("")。如果这里已经有一些数据,例如consttodo=ref("Addsometexthere"):我们的输入字段将加载一些已经添加到输入字段中的文本。无论如何,回到它是一个空字符串,我们在输入字段中键入的任何文本都必须绑定到todo.value。这实际上是一种双向绑定——输入字段可以更新ref()值,而ref()值可以更新输入字段。因此,回顾之前的createNewToDoItem()代码块,我们看到todo.value的内容被推入列表数组-通过将todo.value推入list.value-然后将todo.value更新为空字符串.我们还使用了与React示例中相同的newId()函数。我们如何从列表中删除?反应:constdeleteItem=(id)=>{setList(list.filter((item)=>item.id!==id));};React是如何做到的?因此,即使deleteItem()函数位于ToDo.js中,我也可以通过首先将deleteItem()函数作为道具传递给ToDoItem.js来轻松引用deleteItem()函数:首先把函数传下去,让孩子们使用。然后,在ToDoItem组件内,执行以下操作:deleteItem(item.id)}>-我所要做的就是引用函数参考props.deleteItem。现在您可能已经注意到,在代码示例中我们只是写了deleteItem而不是props.deleteItem。这是因为我们使用了一种称为解构的技术,它允许我们获取道具对象的一部分并将其分配给一个变量。所以在我们的ToDoItem.js文件中,我们有以下内容:constToDoItem=(props)=>{const{item,deleteItem}=props;}这为我们创建了两个变量,一个名为item的变量被调用时分配与props相同的值。item,另一个是deleteItem,它从props.deleteItem中赋值。我们本可以通过使用props.item和props.deleteItem来避免整个破坏性的事情,但我认为值得一提!Vue:functiononDeleteItem(id){list.value=list.value.filter(item=>item.id!==id);}Vue是怎么做的呢?Vue中需要一种稍微不同的方法。我们基本上必须在这里做三件事:首先,在我们要调用函数的元素上:-然后,我们有在子组件(本例中为ToDoItem.vue)中创建一个emit函数作为方法,如下所示:.vue在ToDo.vue中,我们其实引用了一个函数:.它会监听任何使用字符串“delete”触发发射的情况。如果它听到这个消息,它会触发一个名为onDeleteItem的函数。这个函数在ToDo.vue中,不在ToDoItem.vue中。如前所述,此函数仅从list.value数组中过滤ID。这里还值得注意的是,在Vue示例中,我可以像这样在@click侦听器中简单地编写$emit部分:-这会将步骤数从3步减少到2步,这完全取决于个人喜好。简而言之,React中的子组件可以通过props访问父函数(前提是你传递了props,这是相当标准的做法,你会在其他React示例中遇到很多工作),而在Vue中,你可以从子组件发出事件,通常收集在父组件中。我们如何传递事件监听器?React:简单事件侦听器,用于简单事件,例如点击事件。下面是我们如何为创建新ToDo项的按钮创建点击事件的示例:用vanillaJS处理嵌入的onClick。正如Vue部分中提到的,每当按下Enter键时,设置事件侦听器来处理的时间会更长。这本质上要求onKeyPress事件由输入标签处理,例如:只要该函数识别出按下“enter”键,将触发createNewToDoItem函数,例如:constandleKeyPress=(e)=>{if(e.key==="Enter"){createNewToDoItem();}};Vue:在Vue中,它非常简单明了。我们只是使用@符号,然后使用我们想要的事件侦听器类型。因此,例如,要添加一个点击事件监听器,我们可以编写以下代码:单击的简写。Vue事件监听器最酷的一点是你还可以绑定很多东西,比如.once,它可以防止事件监听器被多次触发。在编写用于处理按键的特定事件侦听器时,也有许多快捷方式。我发现在React中创建一个事件侦听器以在按下Enter键时创建一个新的ToDo项需要花费大量时间。在Vue中,我可以简单地写:我们如何将数据传递给子组件?React:在React中,我们将props传递给创建子组件的位置。如:;在这里,我们看到传递给ToDoItem组件的两个道具。从现在开始,我们现在可以通过this.props在子组件中引用它们。因此,要访问item.todo道具,我们只需调用props.item。您可能已经注意到,还有一个关键道具(所以从技术上讲,我们实际上传递了三个道具)。这主要在React内部使用,因为它可以很容易地更新和跟踪同一组件的多个版本的变化(我们在这里有它,因为每个待办事项都是ToDoItem组件的副本)。确保您的组件具有唯一键也很重要,否则React会在控制台中警告您。Vue:在Vue中,我们将props传递给创建子组件的位置。如:完成这个操作后,我们将它们传入子组件的props数组中,如下所示:props:["todo"].然后可以在子组件中通过名称引用这些名称,在我们的例子中就是todo。如果您不确定该prop键放在哪里,下面是整个导出默认对象在子组件中的样子:exportdefault{name:"ToDoItem",props:["item"],setup(props,{emit}){functiondeleteItem(id){emit("delete",id);}return{deleteItem,};},};您可能已经注意到的一件事是,在Vue中迭代数据时,我们实际上只是迭代列表而不是list.value。尝试遍历list.value在这里不起作用我们如何将数据发送回父组件?React:首先,通过将函数作为调用它的prop进行引用,将函数传递给子组件。然后,通过引用props.whateverTheFunctionIsCalled(如果使用解构)或whatTheFunctionIsCalled,您可以通过onClick等任何方式在子元素上添加对函数的调用。然后,这会触发位于父组件中的函数。我们可以在“我们如何从列表中删除”部分看到整个过程的示例。Vue:在子组件中,我们只是写一个函数,返回一个值给父函数。在父组件中,我们编写了一个函数来监听值何时发出,然后可以触发函数调用。我们可以在“我们如何从列表中删除”部分看到整个过程的示例。我们终于明白了!我们已经研究了如何添加、删除和更改数据,将数据作为props从父级传递给子级,以及将数据作为事件侦听器从子级发送到父级。当然,React和Vue之间还有许多其他小差异和怪癖,但希望本文有助于为理解这两个框架如何处理事情奠定基础。如果您有兴趣派生本文中使用的样式,并想制作自己的等效样式,请随意这样做!Github链接到两个应用程序:Vuetodo:https://github.com/sunil-sandhu/vue-todo-2020Reacttodo:https://github.com/sunil-sandhu/react-todo-2020最初发布于:sunilsandhu.com