前言几年前,我决定尝试分别在React和Vue中构建一个相当标准的ToDo应用程序。这两个应用程序都是使用默认CLI构建的(React的create-react-app和Vue的vue-cli)。我想尽量保持中立,并使用这样的示例向您展示这两种技术如何执行特定任务。当ReactHooks发布时,我将这篇文章更新为“2019版”,将类组件替换为函数式Hooks。随着Vue3及其组合API的发布,是时候将本文更新为“2020年版”了。2019版:我用React和Vue构建了同一个app,看看有什么不同我们先来看看两个app的外观:两个app的CSS代码完全一样,只是代码位于不同的地方地方。牢记这一点,让我们看一下它们的文件结构:你会发现它们的结构也几乎相同。唯一的区别是React应用程序有两个CSS文件,而Vue应用程序没有任何CSS文件。这是因为在create-react-app中,默认情况下每个React组件都带有一个单独的文件来保存其样式,而VueCLI使用单个文件来包含默认组件的HTML、CSS和JavaScript。最终他们都实现了相同的目标,没有什么好说的,因为你不能在React或Vue中改变文件结构。选择哪一个真的取决于个人喜好。开发社区中有很多关于CSS结构的讨论,尤其是React,因为有许多CSS-in-JS解决方案,如样式化组件和情感。顺便说一下,CSS-in-JS的字面意思。虽然这些很有用,但这里我们只使用两侧CLI给出的结构。在继续之前,让我们先看看一个典型的Vue和React组件长什么样:我们如何改变数据?首先,“变异数据”到底是什么意思?听起来是不是有点高级?其实基本上就是指改变我们存储的数据。如果我们想将一个人的名字的值从John更改为Mark,我们就是在“改变”数据。这就是React和Vue之间的关键区别所在。Vue本质上创建了一个数据对象,其中数据可以自由更新,而React通过所谓的状态挂钩处理数据突变。从下图中你可以看到两者的设置,然后我们将指定:Reactstate:Vuestate:所以你看到我们将相同的数据传递给两者,但是每个的结构不同。在React中,至少从2019年开始,我们一般通过一系列的Hooks来处理状态。您之前可能没有接触过这个概念,一开始可能会觉得有点奇怪。它基本上是这样工作的:假设我们要创建一个待办事项列表,我们可能需要创建一个名为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被分配了一个函数,该函数使nameRecreate具有新值。在Vue中,它位于setup()函数内部,称为constname=ref('Sunil')。在应用程序中,我们将通过调用name.value来引用它。如果我们想使用在ref()函数中创建的值,我们将在变量上查找.value而不是简单地调用变量。换句话说,如果我们想要保存状态的变量的值,我们将寻找name.value而不是name。如果你想更新name的值,你可以通过更新name.value来实现。例如,假设我想把我的名字从Sunil改成John,我可以写name.value="John"来完成。其实这里React和Vue都在做同样的事情,就是创建可以更新的数据。每次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将提供给我们的新toDo项目。newToDo变量是一个带有id键的对象,其值由newID确定。它还有一个文本键,其值由toDo确定。此待办事项是输入值更改时要更新的待办事项。setList函数就是这样,我们传入一个包含整个列表和新创建的newToDo的数组。你可能会想...list看起来很奇怪:开头的三个点称为展开运算符,负责将列表中的所有值作为单独的项传递,而不是简单地将所有项作为一个项一起传递大批。感到困惑?那么我强烈建议大家仔细阅读传播运算符的介绍,因为它非常有用!最后我们运行setToDo()并传入一个空字符串。这样我们的输入值为空,我们可以输入一个新的toDo。Vue:functioncreateNewToDoItem(){constnewId=generateId();list.value.push({id:newId,text:todo.value});todo.value="";}在Vue中是怎么做的?在Vue中,我们的输入字段有一个名为v-model的句柄。这允许我们做一些叫做双向绑定的事情。让我们看一下输入字段以了解发生了什么:
