React和Vue中创建应用的区别有哪些
本篇内容介绍了"React和Vue中创建应用的区别有哪些"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
React vs Vue:传奇继续
几年前,我决定尝试在React和Vue中构建一个相当标准的To Do App。 这两个应用程序都是使用默认的CLI构建的(React的create-react-app和Vue的vue-cli)。 我的目的是编写无偏见的内容,并提供有关如何使用这两种技术执行某些任务的概述。
当React Hooks发布时,我在原始文章后面加上了" 2019 Edition",该版本将Class Components的使用替换为Functional Hooks。 随着Vue第3版及其成分API的发布,现在是时候以" 2020版"再次更新本文了。
让我们快速看一下这两个应用的外观:
两个应用程序的CSS代码完全相同,但是它们的位置有所不同。 考虑到这一点,接下来让我们看一下两个应用程序的文件结构:
最终,他们俩都能达成同一目标,而且无话可说,您无法继续在React或Vue中以不同的方式构造文件。 这实际上取决于个人喜好。 您将听到来自开发人员社区的大量讨论,关于CSS的结构,尤其是关于React的结构,因为存在许多CSS-in-JS解决方案,例如样式组件和情感。 顺便说一句,CSS-in-JS的字面意义就是这样。 尽管这些功能很有用,但到目前为止,我们将仅遵循两个CLI中列出的结构。
但是在进一步介绍之前,让我们快速看一下典型的Vue和React组件的外观:
典型的React文件:
典型的Vue文件:
既然已经解决了,让我们深入了解细节吧!
我们如何突变数据?
但是首先,"突变数据"甚至意味着什么? 听起来有点技术性吗? 基本上,这只是意味着更改我们已存储的数据。 因此,如果我们想将一个人的名字的值从John更改为Mark,我们将"对数据进行突变"。 因此,这就是React和Vue之间的关键区别所在。 虽然Vue本质上创建了一个数据对象,可以在其中自由更新数据,但是React通过状态钩子来处理它。
让我们看一下下面两个图片中的设置,然后我们将说明发生了什么:
React状态:
Vue状态:
因此,您可以看到我们已经将相同的数据传递给了两者,但是结构有些不同。
使用React或至少从2019年开始,我们通常会通过一系列的Hooks处理状态。 如果您以前没有看过这种概念,那么一开始它们可能看起来有些奇怪。 基本上,它的工作方式如下:
假设我们要创建待办事项列表。 我们可能需要创建一个名为list的变量,它可能需要一个由字符串或对象组成的数组(例如,如果我们想给每个待办事项字符串一个ID和其他一些东西,我们可以通过编写const [ list,setList] = useState([])。这里我们使用React称为Hook的钩子-称为useState。这基本上使我们可以在组件中保留局部状态。
另外,您可能已经注意到我们在useState()内部传入了一个空数组[]。 我们放在其中的是我们希望列表最初设置的内容,在我们的例子中,我们希望是一个空数组。 但是,从上图可以看到,我们在数组内部传入了一些数据,这些数据最终是list的初始化数据。 想知道setList是做什么的? 稍后将对此进行更多说明!
在Vue中,通常会将组件的所有可变数据放置在setup()函数内,该函数返回一个对象,其中包含要公开的数据和函数(这基本上意味着您希望能够使用的东西) 在您的应用中使用)。 您会注意到,应用程序中的每个状态数据(也就是我们希望能够进行突变的数据)都包装在ref()函数内部。 此ref()函数是我们从Vue导入的,可让我们的应用程序在任何更改或更新这些数据时都可以更新。 简而言之,如果您想在Vue中创建可变数据,请为ref()函数分配一个变量,并将任何默认数据放入其中。
那么我们如何在我们的应用程序中引用可变数据呢?
好吧,假设我们有一些名为name的数据被分配了Sunil的值。
在React中,由于我们使用useState()创建了较小的状态,因此很可能已经按照const [name,setName] = useState('Sunil')的方式创建了一些东西。 在我们的应用程序中,我们将通过简单地调用name来引用相同的数据。 现在,这里的主要区别在于我们不能简单地写上name ='John',因为React有适当的限制来防止这种简单,随意的突变产生。 因此,在React中,我们将编写setName('John')。 这是setName位起作用的地方。 基本上,在const [name,setName] = useState('Sunil')中,它将创建两个变量,一个变量将成为const name ='Sunil',而第二个const setName被分配了一个函数,该函数可以使用新的名称重新创建名称。 值。
在Vue中,它位于setup()函数内部,并且被称为const name = ref('Sunil')。 在我们的应用程序中,我们将通过调用name.value来引用它。 使用Vue,如果我们要使用在ref()函数内部创建的值,我们将在变量上寻找.value而不是简单地调用该变量。 换句话说,如果我们想要一个持有状态的变量的值,我们将寻找name.value而不是name。 如果要更新name的值,可以通过更新name.value来完成。 例如,假设我想将我的名字从Sunil更改为John。 我可以通过写name.value =" John"来做到这一点。 我不确定自己被称为约翰的感觉,但是嘿,事情发生了!
实际上,React和Vue在这里做着同样的事情,即创建可以更新的数据。 每当ref()函数内部包装的一条数据被更新时,Vue本质上都会默认结合其自己的name和setName版本。 React要求您使用内部值调用setName()来更新状态,如果您试图更新数据对象内部的值,Vue会假设您要这样做。 那么,为什么React还要从函数中分离值呢?为什么还要使用useState()呢? 本质上,每当状态改变时,React都希望能够重新运行某些生命周期挂钩。 在我们的示例中,如果调用setName(),React将知道某些状态已更改,因此可以运行这些生命周期挂钩。 如果直接改变状态,React将不得不做更多的工作来跟踪更改以及要运行的生命周期挂钩等。
现在,我们已经有了一些变通的方式,让我们通过研究如何将新项目添加到两个"待办事项"中来了解更多细节。
我们如何创建新的待办事项?
React:
const createNewToDoItem = () => { const newId = generateId(); const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };
React是如何做的?
在React中,我们的输入字段具有一个名为value的属性。 每次通过onChange事件侦听器更改其值时,都会自动更新此值。 JSX(基本上是HTML的变体)如下所示:
因此,每次更改值时,它都会更新状态。 handleInput函数如下所示:
const handleInput = (e) => { setToDo(e.target.value); };
现在,每当用户按下页面上的+按钮添加新项目时,都会触发createNewToDoItem函数。 让我们再次看一下该功能,以了解发生了什么:
const createNewToDoItem = () => { const newId = generateId(); const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };
本质上,newId函数基本上是在创建一个新ID,该ID将提供给我们的新toDo项。 newToDo变量是一个具有ID密钥的对象,该ID密钥具有newId的值。 它还具有一个文本键,该键将toDo中的值用作其值。 这与输入值更改时要更新的toDo相同。
然后,我们用完setList函数,并传入一个包含整个列表以及新创建的newToDo的数组。
如果… list位看起来很奇怪,则开头的三个点称为散布运算符,它基本上将列表中的所有值作为单独的项目传递,而不是简单地传递完整的 项目作为数组。 困惑? 如果是这样,我强烈建议您仔细阅读散布,因为它很棒!
无论如何,最后我们运行setToDo()并传入一个空字符串。 这样我们的输入值为空,可以输入新的toDos了。
Vue:
function createNewToDoItem() { const newId = generateId(); list.value.push({ id: newId, text: todo.value }); todo.value = ""; }
Vue是如何做的?
在Vue中,输入字段上有一个称为v-model的句柄。 这使我们能够执行称为双向绑定的操作。 让我们快速查看一下输入字段,然后说明发生了什么:
V-Model将该字段的输入与我们在setup()函数顶部创建的变量绑定在一起,然后将其作为键公开给我们返回的对象。 到目前为止,我们还没有介绍对象返回的内容,因此,对于您的信息,这是我们从ToDo.vue内部的setup()函数返回的内容:
return { list, todo, showError, generateId, createNewToDoItem, onDeleteItem, displayError};
这里,list,todo和showError是我们的有状态值,而其他所有功能都是我们希望能够在应用程序其他位置调用的函数。 好的,从切线返回,当页面加载时,我们必须将todo设置为空字符串,例如:const todo = ref("")。 如果这里已经有一些数据,例如const todo = ref("在此处添加一些文本"):我们的输入字段将在输入字段内部已经添加一些文本的情况下加载。 无论如何,回到它作为一个空字符串,无论我们在输入字段中键入什么文本都必须绑定到todo.value。 这实际上是双向绑定-输入字段可以更新ref()值,而ref()值可以更新输入字段。
因此,回顾一下前面的createNewToDoItem()代码块,我们看到将todo.value的内容推入列表数组-通过将todo.value推入list.value-然后将todo.value更新为空字符串。
我们还使用了与React示例中相同的newId()函数。
我们如何从列表中删除?
React:
const deleteItem = (id) => { setList(list.filter((item) => item.id !== id)); };
React是如何做的?
因此,尽管deleteItem()函数位于ToDo.js内,但我很容易能够通过首先将deleteItem()函数作为道具传递给ToDoItem.js来对其进行引用:
首先,该函数向下传递,以使儿童可以使用它。 然后,在ToDoItem组件内部,执行以下操作:
我要做的就是引用位于父组件内部的函数,就是引用props.deleteItem。 现在您可能已经注意到,在代码示例中,我们只是编写了deleteItem而不是props.deleteItem。 这是因为我们使用了一种称为解构的技术,该技术允许我们获取props对象的一部分并将其分配给变量。 因此,在我们的ToDoItem.js文件中,我们具有以下内容:
const ToDoItem = (props) => { const { item, deleteItem } = props; }
这为我们创建了两个变量,一个称为item,它被分配与props.item相同的值,另一个是deleteItem,它从props.deleteItem分配了值。 我们本可以通过仅使用props.item和props.deleteItem来避免整个破坏性的事情,但是我认为值得一提!
Vue:
function onDeleteItem(id) { list.value = list.value.filter(item => item.id !== id); }
Vue是如何做的?
Vue中需要一种略有不同的方法。 我们基本上必须在这里做三件事:
首先,在元素上我们要调用函数:
然后,我们必须在子组件(在本例中为ToDoItem.vue)中创建一个emit函数作为方法,如下所示:
function deleteItem(id) { emit("delete", id);}
同时,您会注意到,当我们在ToDo.vue中添加ToDoItem.vue时,我们实际上引用了一个函数:
这就是所谓的自定义事件侦听器。 它会侦听在任何情况下使用字符串" delete"触发发射的情况。 如果听到此消息,它将触发一个名为onDeleteItem的函数。 此函数位于ToDo.vue内部,而不是ToDoItem.vue中。 如前所述,此函数仅从list.value数组中过滤ID。
在这里还值得注意的是,在Vue示例中,我可以简单地将$ emit部分写在@click监听器中,如下所示:
这将使步数从3减少到2,而这完全取决于个人喜好。
简而言之,React中的子组件可以通过props来访问父函数(前提是您要传递props,这是相当标准的做法,在其他React示例中,您会遇到大量的工作),而在Vue中,您可以 从孩子发出事件,通常将其收集在父组件中。
我们如何传递事件监听器?
React:
简单事件(例如单击事件)的事件侦听器很简单。 这是我们如何为创建新的ToDo项目的按钮创建click事件的示例:
在这里超级简单,几乎就像我们将如何使用香草JS处理嵌入式onClick。 如Vue部分所述,每当按下Enter键时,设置事件侦听器进行处理就花费了更长的时间。 这本质上需要由输入标签处理onKeyPress事件,例如:
只要该函数识别出已按下" enter"键,便会触发createNewToDoItem函数,例如:
const handleKeyPress = (e) => { if (e.key === "Enter") { createNewToDoItem(); } };
Vue:
在Vue中,它非常简单明了。 我们只使用@符号,然后使用我们想要做的事件监听器的类型。 因此,例如,要添加一个click事件监听器,我们可以编写以下代码:
注意:@click实际上是编写v-on:click的简写。 Vue事件侦听器很酷的事情是,您还可以绑定很多东西,例如.once,它可以防止事件侦听器被多次触发。 在编写用于处理按键的特定事件侦听器时,还有许多捷径。 我发现,每当按下Enter键时,在React中创建一个事件侦听器以创建新的ToDo项就花费了相当长的时间。 在Vue中,我能够简单地编写:
我们如何将数据传递给子组件?
反应:
在react中,我们将道具传递到子组件的创建位置。 如:
;
在这里,我们看到两个传递给ToDoItem组件的道具。 从现在开始,我们现在可以通过this.props在子组件中引用它们。 因此,要访问item.todo prop,我们只需调用props.item。 您可能已经注意到,还有一个关键道具(因此从技术上讲,我们实际上正在传递三个道具)。 这主要用于React的内部,因为它使在同一组件的多个版本之间进行更新和跟踪更改变得容易(我们在这里拥有它,因为每个todo是ToDoItem组件的一个副本)。 确保您的组件具有唯一键也很重要,否则React会在控制台中警告您。
Vue:
在Vue中,我们将道具传递到子组件的创建位置。 如:
完成此操作后,我们将它们传递到子组件的props数组中,如下所示:props:[" todo"]。 然后可以通过子组件的名字在子组件中引用这些名字,因此在我们的案例中是todo。 如果您不确定该prop键的放置位置,则这是整个导出默认对象在子组件中的外观:
export default { name: "ToDoItem", props: ["item"], setup(props, { emit }) { function deleteItem(id) { emit("delete", id); } return { deleteItem, }; }, };
您可能已经注意到的一件事是,当在Vue中遍历数据时,我们实际上只是遍历了list而不是list.value。 尝试遍历list.value在这里行不通
我们如何将数据发送回父组件?
React:
首先,通过在调用子组件的地方将其作为道具引用,将函数传递给子组件。 然后,通过引用props.whateverTheFunctionIsCalled(如果使用了解构)或whatTheFunctionIsCalled,可以通过诸如onClick之类的任何方式在子元素上添加对函数的调用。 然后,这将触发位于父组件中的函数。 我们可以在"我们如何从列表中删除"部分中看到整个过程的示例。
Vue:
在子组件中,我们只编写了一个将值返回给父函数的函数。 在父组件中,我们编写了一个函数,该函数侦听何时发出该值,然后可以触发函数调用。 我们可以在"我们如何从列表中删除"部分中看到整个过程的示例。
"React和Vue中创建应用的区别有哪些"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!