Creé la misma aplicación en React & Vue. Aquí las diferencias.


Traducción del texto original de Sunil Sandhu “I created the exact same app in React and Vue. Here are the differences.”


Al usar Vue en el trabajo, tenía una comprensión bastante sólida de ello. Sin embargo, tenía curiosidad por saber cómo era el pasto al otro lado de la cerca: el pasto en este escenario es React.

Leí los documentos de React y vi algunos videos de tutoriales y, aunque fueron geniales, lo que realmente quería saber era qué tan diferente era React de Vue. Por “diferente”, no quise decir cosas tales como si ambos tenían DOMS virtuales o cómo iban a hacer las páginas. ¡Quería que alguien se tomara el tiempo para explicar el código y decirme qué estaba pasando! Quería encontrar un artículo que se tomara el tiempo de explicar estas diferencias para que alguien nuevo en Vue o React (o en Desarrollo Web en general) pudiera comprender mejor las diferencias entre los dos.

Pero no pude encontrar nada que abordara esto. Entonces me di cuenta de que tendría que seguir adelante y construir esto por mí mismo para ver las similitudes y diferencias. Al hacerlo, pensé que documentaría todo el proceso para que finalmente exista un artículo sobre esto.

¿Quién lo hace mejor?

Decidí probar y construir una aplicación de tareas bastante estándar que permita a un usuario agregar y eliminar elementos de la lista. Ambas aplicaciones se crearon utilizando los CLI predeterminados (create-react-app para React y vue-cli para Vue). CLI es sinónimo de interfaz de línea de comandos, por cierto. 🤓

De todos modos, esta introducción ya es más larga de lo que había anticipado. Así que comencemos echando un vistazo rápido al aspecto de las dos aplicaciones:

Vue vs React: La irresistible fuerza conoce al objeto inmóvil.

El código CSS para ambas aplicaciones es exactamente el mismo, pero hay diferencias en el lugar donde se encuentran. Con eso en mente, veamos a continuación la estructura de archivos de ambas aplicaciones:

¿Quién lo hace mejor?

Verás que sus estructuras también son casi idénticas. La única diferencia aquí es que la aplicación React tiene tres archivos CSS, mientras que la aplicación Vue no tiene ninguno. La razón de esto es que, en create-react-app, un componente React tendrá un archivo de acompañamiento para guardar sus estilos, mientras que Vue CLI adopta un enfoque que abarca todo, donde los estilos se declaran dentro del archivo de componente real.

En última instancia, ambos logran lo mismo, y no hay nada que decir que no puede seguir adelante y estructurar su CSS de manera diferente en React o Vue. Realmente se trata de preferencias personales: escucharás mucha discusión de la comunidad de desarrolladores sobre cómo debería estructurarse el CSS. Por ahora, solo seguiremos la estructura establecida en ambas CLI.

Pero antes de continuar, echemos un vistazo rápido a cómo se ven los componentes típicos de Vue y React:

Vue a la izquierda, React a la derecha

Ahora que esto está claro, vamos a revisar en detalle…

¿Cómo mutamos los datos?

Pero primero, ¿qué queremos decir con “mutar los datps”? Suena un poco técnico ¿no? Básicamente solo significa cambiar los datos que hemos almacenado. Entonces, si quisiéramos cambiar el valor del nombre de una persona de John a Mark, estaríamos “mutando los datos”. Así que aquí es donde radica una diferencia clave entre React y Vue. Mientras que Vue esencialmente crea un objeto de datos, donde los datos se pueden actualizar libremente, React crea un objeto de estado, donde se requiere un poco más de trabajo para realizar las actualizaciones. Ahora React implementa el trabajo extra por una buena razón, y nos ocuparemos de eso en un momento. Pero primero, echemos un vistazo al objeto de datos de Vue y al objeto de estado de React:

Objeto de datos de Vue a la izquierda, Objeto de estado de React a la derecha.

Así que puedes ver que hemos pasado la misma información a ambos, pero están etiquetados de manera diferente. Por lo tanto, pasar datos iniciales a nuestros componentes es muy, muy similar. Pero como hemos mencionado, la forma en que cambiamos estos datos difiere entre ambos marcos (Frameworks).

Ejemplificando

Digamos que tenemos un elemento de datos llamado name: “Sunil”.

En Vue, hacemos referencia a esto llamando this.name. También podemos actualizar esto llamando a this.name = “John”. Esto cambiaría mi nombre a John. No estoy seguro de cómo me siento cuando me llaman John, pero ¡oye, las cosas pasan! 😅

En React, haríamos referencia al mismo dato llamando this.state.name. Ahora, la diferencia clave aquí es que no podemos simplemente escribir this.state.name = “John”, porque React tiene restricciones establecidas para evitar este tipo de creación de mutaciones fácil y sin problemas. Así que en React, deberíamos escribiríamos algo así en la línea de código this.setState ({name: ‘John’}).

Si bien esto esencialmente hace lo mismo que hemos logrado en Vue, el bit extra de escritura está allí porque Vue esencialmente combina su propia versión de setState por defecto cada vez que se actualiza una parte de los datos. En resumen, React requiere setState y luego los datos actualizados dentro de él, mientras que Vue asume que usted querría hacer esto si estuviera actualizando valores dentro del objeto de datos. Entonces, ¿por qué React se molesta con esto y por qué es necesario setState? Vamos a pasar esto a Revanth Kumar para una explicación:

“Esto se debe a que React desea volver a ejecutar ciertos enlaces de ciclo de vida, [por ejemplo] componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate, siempre que el estado cambie. Sabría que el estado ha cambiado cuando llama a la función setState. “Si cambia directamente el estado, React tendría que hacer mucho más trabajo para realizar un seguimiento de los cambios y qué ganchos de ciclo de vida ejecutar, etc. Así que para hacerlo simple, React usa setState”.

Ahora que tenemos las mutaciones fuera del camino, entenderemos cómo iríamos agregando nuevos elementos a nuestras dos aplicaciones de tareas.

¿Cómo creamos nuevos items en nuestra aplicación de tareas?

REACT:

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

¿Cómo lo hace React?

En React, nuestro campo de entrada tiene un atributo llamado Value (Valor). Este valor se actualiza automáticamente mediante el uso de un par de funciones que se unen para crear algo que se parece mucho a la vinculación bidireccional two-way binding (si nunca ha oído hablar de esto antes, hay una explicación más detallada en la sección ¿Cómo hizo Vue esa sección?) después de este). Creamos esta forma de enlace bidireccional al tener un onChange event listener (detector de eventos onChange) adicional adjunto al input (campo de entrada). Veamos rápidamente el campo de entrada para que podamos ver lo que está pasando:

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

La función handleInput se ejecuta siempre que cambia el valor del campo de entrada. Actualiza la tarea pendiente que se encuentra dentro del objeto de estado configurándolo en lo que sea que esté en el input (campo de entrada). Esta función se ve como tal:

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

Ahora, cada vez que un usuario presiona el botón + en la página para agregar un nuevo elemento, la función createNewToDoItem esencialmente ejecuta this.setState y le pasa una función. Esta función toma dos parámetros, el primero es la matriz de lista (completa del objeto de estado y el segundo es todo (que se actualiza por la función handleInput). La función luego devuelve un nuevo objeto, que contiene la lista completa de antes y luego agrega todo al final de la misma. La lista completa se agrega mediante el uso de un operador de propagación (Google, si no lo ha visto antes, es sintaxis de ES6).

Finalmente, establecemos todo en una cadena vacía, que actualiza automáticamente el valor dentro del campo de entrada.

VUE:

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

¿Cómo hizo Vue eso?

En Vue, nuestro input (campo de entrada) tiene un controlador llamado v-model. Esto nos permite hacer algo conocido como two-way binding enlace bidireccional. Veamos rápidamente nuestro campo de entrada, luego explicaremos lo que está pasando:

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

V-Model vincula la entrada de este campo a una clave que tenemos en nuestro objeto de datos llamado toDo Item. Cuando se carga la página, tenemos que DoItem establecido en una cadena vacía, como tal: todo: ‘’. Si esto tuviera algunos datos ya allí, como por ejemplo: “agregar texto aquí”, nuestro campo de entrada se cargaría con algo de texto aquí dentro del campo de entrada. De todos modos, volviendo a tenerla como una cadena vacía, cualquier texto que escribamos dentro del campo de entrada queda vinculado al valor de todo. Esto es efectivamente un enlace bidireccional (el campo de entrada puede actualizar el objeto de datos y el objeto de datos puede actualizar el campo de entrada).

Así que al mirar hacia atrás en el bloque de código createNewToDoItem () anterior, vemos que insertamos el contenido de todo en la matriz (Array) de la lista y luego actualizamos todo a una cadena vacía.

¿Cómo eliminamos de la lista?

REACT:

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

¿Cómo lo hace React?

Por lo tanto, aunque la función deleteItem se encuentra dentro de ToDo.js, pude hacer referencia a ella dentro de ToDoItem.js al pasar la función deleteItem () como una propiedad de <ToDoItem /> como tal:

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

Esto primero pasa la función hacia abajo para que sea accesible para el child. Verá aquí que también estamos vinculando esto, así como pasando el parámetro clave, ya que la clave es lo que la función utilizará para poder diferenciar entre los que ToDoItem intenta eliminar cuando se hace clic. Luego, dentro del componente ToDoItem, hacemos lo siguiente:

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

Todo lo que tenía que hacer para hacer referencia a una función que estaba dentro del componente principal era hacer referencia a this.props.deleteItem.

VUE:

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

¿Cómo hizo Vue eso?

Se requiere un enfoque ligeramente diferente en Vue. Básicamente tenemos que hacer tres cosas aquí:

En primer lugar, en el elemento queremos llamar a la función:

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

Luego tenemos que crear una función de emisión como un método dentro del componente secundario (en este caso, ToDoItem.vue), que tiene este aspecto:

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

Junto con esto, notará que realmente hacemos referencia a una función cuando agregamos ToDoItem.vue dentro de ToDo.vue:

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

Esto es lo que se conoce como un detector de eventos personalizado. Escucha cualquier ocasión en la que se emita un emisor con la cadena de “eliminar”. Si escucha esto, activa una función llamada onDeleteItem. Esta función se encuentra dentro de ToDo.vue, en lugar de ToDoItem.vue. Esta función, como se indicó anteriormente, simplemente filtra la matriz de tareas dentro del objeto de datos para eliminar el elemento en el que se hizo clic.

También vale la pena señalar aquí que en el ejemplo de Vue, simplemente podría haber escrito la parte $emit a dentro del oyente @click, como tal:

<div class=”ToDoItem-Delete” @click=”$emit(‘delete’, todo)”>-</div>

Esto habría reducido el número de pasos de 3 a 2, y esto es simplemente una preferencia personal.

En resumen, los componentes secundarios en React tendrán acceso a las funciones de los padres a través de this.props (siempre que esté pasando los apoyos, lo cual es una práctica bastante estándar y encontrará este montón de veces en otros ejemplos de React), mientras que en Vue, tiene que emitir eventos del elemento secundario que normalmente se recopilarán dentro del componente principal.

¿Cómo pasamos a un llamado de evento?

REACT:

Las listas de eventos para cosas simples como eventos de clic son sencillos. Este es un ejemplo de cómo creamos un evento de clic para un botón que crea un nuevo elemento ToDo:

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

Súper fácil aquí y se parece bastante a cómo manejaríamos un onClick en línea con vanilla JS. Como se mencionó en la sección Vue, se tardó un poco más en configurar un detector de eventos para que lo manejara cada vez que se presionaba el botón Enter. Esto esencialmente requería que un evento onKeyPress fuera manejado por la etiqueta de entrada, como tal:

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

Esta función esencialmente activa la función createNewToDoItem cada vez que reconoce se ha presionado la tecla ‘enter’, como tal:

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

VUE:

En Vue es super sencillo. Simplemente usamos el símbolo @ y luego el tipo de escucha de eventos que queremos hacer. Por ejemplo, para agregar un detector de eventos de clic, podríamos escribir lo siguiente:

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

Nota: @click es en realidad un atajo de teclado para escribir v-on: click. Lo bueno de los oyentes de eventos de Vue es que también hay un montón de cosas que puedes encadenar a ellos, como .once, que evita que el oyente de eventos se active más de una vez. También hay un montón de atajos cuando se trata de escribir llamados de eventos específicos para manejar desde el teclado. Descubrí que me tomó un poco más de tiempo crear un detector de eventos en React para crear nuevos elementos de tareas pendientes cada vez que se presionaba el botón de entrada. En Vue, pude escribir simplemente:

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

¿Cómo pasamos los datos a un child component (componente secundario)?

REACT:

En React, pasamos los accesorios al componente hijo en el punto donde se crea. Como:

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

Aquí vemos dos arreglos pasan al componente ToDoItem. A partir de este momento, ahora podemos hacer referencia a ellos en el componente secundario a través de this.props. Entonces, para acceder al artículo item.todo prop, simplemente llamamos this.props.item.

VUE:

En Vue, pasamos los arreglos al componente hijo en el punto donde se crea. Como:

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

Una vez hecho esto, los pasamos a la matriz de accesorios en el componente hijo, como tal: props: [‘todo’]. Estos pueden ser referenciados en el hijo por su nombre, por lo tanto, en nuestro caso, “todo”.

¿Cómo emitimos datos a un parent component (componente principal)?

REACT:

En primer lugar, pasamos la función al componente secundario haciendo referencia a ella como elemento de apoyo en el lugar donde llamamos al componente secundario. Luego agregamos la llamada a la función en el hijo por cualquier medio, como onClick, haciendo referencia a this.props.whateverTheFunctionIsCalled. Esto activará la función que se encuentra en el componente principal. Podemos ver un ejemplo de todo este proceso en la sección “Cómo eliminamos de la lista”.

VUE:

En nuestro componente secundario, simplemente escribimos una función que emite un valor a la función principal. En nuestro componente principal, escribimos una función que escucha cuándo se emite ese valor, que luego puede desencadenar una llamada de función. Podemos ver un ejemplo de todo este proceso en la sección “Cómo eliminamos de la lista”.

¡Y ahí lo tenemos! 🎉

Hemos examinado cómo agregamos, eliminamos y cambiamos datos, pasamos datos en forma de apoyo de padres a hijos y enviamos datos del hijo al padre en forma de escuchas de eventos. Hay, por supuesto, muchas otras pequeñas diferencias y peculiaridades entre React y Vue, pero esperamos que el contenido de este artículo haya servido como una base para entender cómo ambos frameworks manejan las cosas. 🤓

Si encuentra esto útil, asegúrese de dar muchos y muchos aplausos.👏 Pista, puedes dejar hasta 50! 😉

Texto Original

Inglés

Y ¿qué pasa con Angular? 😄

Hay una segunda parte de este artículo ;) espérala la próxima semana.

Github links a ambas aplicaciones:


🤓Sí tienes un comentario adicional, aquí puedes dejarlo. 👇