1. Introducción a Rev vs. Reactive en Vue 3
Bienvenidos a mi charla, Rev vs. Reactive. Explicaré cómo pueden elegir si usar Rev, Reactive o ambos. Exploraremos los conceptos básicos de la reactividad en Vue 3 y compararemos Reactive y Rev. Por último, discutiré las opiniones de la comunidad de Vue y compartiré un patrón recomendado para agrupar Rev y Reactive.
Hola amantes de Vue de todo el mundo. Bienvenidos a mi charla, Rev vs. Reactive. Cómo elegir usar la API de composición de Vue 3. Mi nombre es Michael Hoffman. Soy un desarrollador front-end senior y freelancer de Munich, Alemania. Estoy enfocado en Vue.js y dirijo un boletín semanal de Vue y soy muy activo en Twitter. Así que asegúrate de saludar allí. Empecemos.
Me encanta la API de composición de Vue 3, pero proporciona dos enfoques para agregar estado reactivo a los componentes de Vue. Puedes elegir entre Rev o Reactive. Puede ser engorroso usar .value en todas partes al usar Revs. Por otro lado, puedes perder fácilmente la reactividad al desestructurar objetos reactivos. Así que en esta charla, te explicaré cómo puedes elegir si usar Rev, Reactive o ambos. Primero, necesito explicar algunos conceptos básicos de la reactividad en Vue 3. Luego, analizaremos detalladamente Reactive y Rev. Haremos una comparación entre ambos. Y al final, habrá una conclusión donde hablaré sobre mi opinión y las opiniones de la comunidad de Vue. Y te mostraré un patrón recomendado de cómo puedes agrupar Rev y Reactive.
2. Reactividad en Vue 3
La reactividad en Vue 3 es crucial para mantener el modelo y Vue sincronizados. JavaScript no es reactivo por defecto, por lo que Vue utiliza proxies y getter-setters para implementar la reactividad. La función reactive devuelve un objeto proxy reactivo basado en el objeto proporcionado. Es similar a vue.observable en Vue 2 y crea un estado profundamente reactivo.
Comencemos con la reactividad en Vue 3. ¿Qué es la reactividad y por qué Vue la necesita? Un sistema de reactividad es un mecanismo que mantiene automáticamente sincronizada una fuente de datos, nuestro modelo, con una representación de datos, nuestro Vue. Si el modelo cambia, Vue se vuelve a renderizar para reflejar los cambios. Este mecanismo es crucial para cualquier framework web.
Pero JavaScript no es reactivo por defecto. Veamos un ejemplo de código. Aquí tenemos una variable precio con el valor 10 y una variable cantidad con el valor 2. Calculamos el total multiplicando el precio y la cantidad. Si registramos el total, obtenemos 20 como se esperaba. Pero, ¿qué sucede si ahora asignamos un nuevo valor al precio, por ejemplo, 20? Si ahora registramos el resultado, el total sigue siendo 20. En un sistema de reactividad, esperaríamos que el total se actualice cada vez que se cambie el precio o la cantidad. Pero JavaScript normalmente no funciona así. Esa es la razón por la cual el framework Vue tuvo que implementar otro mecanismo para rastrear la lectura y escritura de variables locales.
¿Cómo implementa Vue la reactividad? Funciona interceptando la lectura y escritura de las propiedades de los objetos. Por lo tanto, Vue 3 utiliza proxies para objetos reactivos y getter-setters para refs. Veamos los ejemplos de código simplificados, que ignoran muchos casos especiales y detalles. Tenemos una función reactive que recibe un objeto. Dentro de la función, devolvemos un nuevo objeto proxy basado en el objeto dado pasado como argumento a la función. El getter del objeto proxy recibe un mapa de destino, que almacena efectos, que son funciones que modifican el estado de la aplicación. La función track se utiliza para verificar si hay un efecto en ejecución actualmente, y luego el getter devuelve el efecto en el mapa de destino para la clave dada. El setter también recibe el mapa de destino, la clave y el valor de nuestro efecto. La función trigger busca los efectos suscritos para la propiedad y los invoca. No es necesario entender todos los detalles que ocurren en este ejemplo de código, pero lo que debes recordar es que Vue 3 utiliza objetos para implementar la reactividad. Solo para tu información, Vue 2 utilizaba exclusivamente getter-setters de objetos debido a limitaciones del navegador. Ahora veamos la función reactive. Devuelve un proxy reactivo del objeto proporcionado. Podemos importar reactive desde el paquete Vue y luego llamar a la función y pasar cualquier objeto, como en nuestro ejemplo, count: 0. Esto es equivalente a vue.observable, que estaba disponible en Vue versión 2. El estado creado con la función reactive es profundamente reactivo por defecto. En este ejemplo, definimos un nuevo estado llamando a la función reactive.
3. Limitaciones de Reactive en Vue 3
Definimos un watcher que muestra correctamente el estado inicial. Las limitaciones de reactive incluyen trabajar exclusivamente con tipos de objeto y no tener la misma identidad que el objeto original. Desestructurar una propiedad de un objeto reactivo en una variable local desconecta la reactividad. Vue proporciona una solución con la función two refs. Otro problema surge al reasignar un valor reactivo, lo que provoca la pérdida de la conexión de reactividad.
Y pasamos el objeto, que contiene un contador cero y un objeto anidado adicional que también contiene un contador cero. Definimos un watcher que observa nuestro estado y bloquea el estado cada vez que cambia. Por lo tanto, mostrará correctamente el estado inicial. Pero, ¿qué sucede si ahora llamamos a un método de incremento que incrementa nuestro contador anidado usando state.nested.count? Y si actualizamos este valor anidado, el watcher también se activa porque es profundamente reactivo de forma predeterminada.
Echemos un vistazo a algunas limitaciones de reactive. La API reactiva tiene dos limitaciones. La primera es que funciona exclusivamente con tipos de objeto como objetos, arrays o tipos de colección como map o set. Y no funciona con tipos primitivos como string, number o Boolean. La segunda limitación es que el objeto proxy devuelto por reactive no tiene la misma identidad que el objeto original. Por lo tanto, definimos un objeto JavaScript plano. Llamamos a la función reactive y pasamos el objeto JavaScript plano. La función reactive devuelve un nuevo objeto proxy. Si ahora hacemos una comparación utilizando el operador de igualdad estricta entre el objeto proxy y el objeto JavaScript plano, el resultado será falso, lo que significa que no tienen la misma identidad.
Tenemos un problema debido a la diferente identidad entre el proxy y el objeto original, y esto ocurre si intentas desestructurar una propiedad de un objeto reactivo en una variable local. Tenemos un estado con un contador reactivo de 0. Y si ahora intentas desestructurar el contador en una variable local, esto desconecta la reactividad de state.count. Por lo tanto, si intentas incrementar el contador, esto no afectará al estado original porque el contador ahora es un número plano y no activará ningún watcher, por ejemplo. Así que debes tener cuidado ahí. Afortunadamente, Vue proporciona una solución para eso, y es la función two refs. Tenemos, nuevamente, nuestro estado con un contador de 0. Podemos importar two refs desde el paquete Vue. La función two refs acepta un argumento y podemos pasar nuestro objeto proxy reactivo. Luego, podemos desestructurar sus propiedades. Y la propiedad desestructurada es un ref y mantiene la reactividad. Así que ten cuidado si intentas desestructurar objetos reactivos.
Hay un segundo problema debido a las diferentes identidades, y aparece si intentas reasignar un valor reactivo. Tenemos nuestro estado con un contador de 0. Definimos un watcher para el estado, que bloquea nuestro estado inicial. Pero si intentas reasignar un objeto reactivo completamente nuevo a nuestra variable de estado, esto no funcionará porque la referencia ya no se está rastreando y se pierde nuestra conexión de reactividad.
4. Watcher, Identity, and Migration
Ten cuidado con el watcher que no se dispara y la identidad diferente entre el proxy y el objeto original. Pasar una propiedad a una función puede causar problemas. Reactive es una buena opción para la migración de la API de composición. Copia todo desde data a reactive para migrar componentes.
Entonces, el watcher no se disparará. Así que ten cuidado aquí. Esto también puede causar problemas complicados en tu aplicación.
Hay un tercer problema con la identidad diferente entre el proxy y el objeto original al usar la función reactive. Y ocurre si intentas pasar una propiedad a una función.
Echemos un vistazo a nuestro estado con un contador de 0. Y ahora queremos pasar el contador accedido por state.count a una función útil. La función útil recibe el contador, pero el contador aquí es un número plano y ya no es reactivo. Así que ten cuidado aquí. Esto también puede causar errores complicados en tu código.
Pero reactive es una buena opción para la migración de la API de composición porque reactive funciona de manera muy similar a las propiedades reactivas dentro del campo data. Este es el código de nuestro componente de API de opciones con el campo data que contiene un objeto con un contador de 0 y un nombre myCounter. Simplemente podemos copiar todo desde data a reactive para migrar este componente a la API de composición. Este es el mismo componente utilizando la API de composición. Y como puedes ver, puedes copiar y pegar el mismo objeto en la función reactive. Y eso es bastante útil para hacer una migración a la API de composición.
5. Función Ref y Reactividad
Ref aborda las limitaciones de reactive y puede contener cualquier tipo de valor, incluyendo valores primitivos y tipos de datos complejos. Para crear una variable reactiva usando ref, importamos ref desde el paquete view y pasamos un valor primitivo u objeto como valor inicial. Para leer y modificar la variable reactiva, se accede a la propiedad value. Internamente, ref crea un nuevo objeto con un getter y un setter, utilizando las mismas funciones de seguimiento y activación que reactive. Ref también utiliza reactive internamente para los tipos de objeto. Sin embargo, la desestructuración de un ref o reasignar count.value desconecta la reactividad.
Ahora echemos un vistazo a la función ref. Y ref aborda las limitaciones de reactive. Ref no se limita a los tipos de objeto, sino que puede contener cualquier tipo de valor. Por lo tanto, podemos usarlo para valores primitivos como cadenas, números y booleanos. Pero también puede almacenar tipos de datos complejos como objetos, matrices o incluso elementos DOM.
Podemos importar ref desde el paquete view. Luego podemos crear una variable reactiva utilizando la función ref. Y podemos pasar un valor primitivo como cero o un objeto como en este ejemplo count cero. Para leer y escribir en las variables reactivas creadas con ref, necesitamos llamar a la propiedad value. Así que tenemos nuevamente nuestro count con ref cero. Si ahora registramos count, podemos ver que devuelve un objeto con valor cero. Por lo tanto, para acceder al valor, debemos llamar a count.value. Para modificar la variable reactiva, también debemos llamar a count.value. En este ejemplo, queremos establecer count en dos. Entonces debemos llamar a count.value y establecer su valor en dos. Si registras el resultado, puedes ver que el valor se actualiza correctamente a dos.
Echemos un vistazo a los detalles internos de ref porque tal vez te preguntes cómo puede ref contener valores primitivos después de haber aprendido que el sistema de reactividad de Vue se basa en interceptar la lectura y escritura de objetos y un valor primitivo no es un objeto. Así que echemos un vistazo al código simplificado con fines de demostración que muestra cómo funciona ref internamente. Tenemos la función ref que recibe un valor, en este caso cualquier valor primitivo como una cadena, booleano o número. Y dentro de la función ref, se crea un nuevo objeto que también se devuelve desde aquí. Y dentro del objeto, tenemos un getter y un setter. Ambos utilizan las mismas funciones de seguimiento y activación que ya hemos discutido en la sección de reactividad. Lo interesante es que ref utiliza reactive internamente si se pasa un tipo de objeto como una matriz u objeto. Entonces, en términos simplificados, llamar a ref con un objeto es casi lo mismo que llamar a ref con reactive y un objeto.
Hablemos sobre la desestructuración de un ref porque la reactividad también se pierde si intentas desestructurar un objeto reactivo creado con ref. Tenemos nuestro count con ref cero. Y si ahora intentamos desestructurar el valor de count, esto desconecta la reactividad. Y la variable count desestructurada sería un número plano en este ejemplo. Lo mismo ocurre si reasignas count.value a una nueva variable, en este ejemplo, count.value.
6. Reactividad y Refs en Vue 3
Para mantener la reactividad al trabajar con refs, puedes agruparlos en un objeto JavaScript simple. Pasar refs a funciones preserva la reactividad y es útil para extraer lógica en componentes. Los refs pueden ser reemplazados por nuevas referencias de objeto sin perder la reactividad. Vue desenrolla automáticamente los refs en plantillas y dependencias de watchers. La función de utilidad unwrap desenrolla correctamente los refs, facilitando el trabajo con variables reactivas.
Esto también desconecta la reactividad y count.value también sería un número plano. Así que también debes tener cuidado aquí. Una solución sería agrupar tus refs en un objeto JavaScript simple. Entonces aquí tenemos state, que es un objeto JavaScript simple que contiene una propiedad con el valor ref uno, y otra propiedad name que contiene un ref con Michael. Y ahora puedes desestructurar count y name del objeto state, y ambos seguirán siendo reactivos porque ambos son refs.
Hablemos de pasar refs a funciones. Porque puedes hacerlo sin perder la reactividad. Tenemos nuevamente nuestro ejemplo de state con un ref count uno y un ref name Michael, y ahora queremos pasar count a useFoo. UseFoo recibe un argumento count, que es un ref y es completamente reactivo. Así que si recuerdas, esto ahora es completamente reactivo en comparación con reactive, donde se perdió la reactividad en el mismo ejemplo. Y esta capacidad es bastante importante, ya que se usa con frecuencia cuando extraes tu lógica en componentes.
Intentemos ahora reemplazar un objeto ref con una nueva referencia de objeto. En este ejemplo, hemos definido una nueva variable reactiva state llamando a ref con un objeto que contiene count uno y name Michael. Ahora queremos reasignar un objeto completamente nuevo. En este ejemplo, llamamos a state.value y pasamos y referenciamos un nuevo objeto con count dos y name Chris. Y esto funciona usando ref y el state sigue siendo reactivo. Así que esta es una gran ventaja en comparación con usar reactive. En este capítulo, echamos un vistazo a desenrollar refs porque Vue nos ayuda a desenrollar los refs sin llamar a .value en todas partes. Primero, Vue desenrolla automáticamente un ref cuando lo llamas en la plantilla. Así que aquí tenemos dentro de la configuración del script, nuestro count con ref cero. Y en la plantilla, no necesitamos llamar a count.value porque Vue desenrolla automáticamente nuestro ref aquí. Lo mismo ocurre con las dependencias de los watchers. Tenemos nuestro count con el ref cero. Y el primer argumento de la función watch con la dependencia del watcher. Y aquí no necesitamos llamar a .value porque Vue desenrolla automáticamente el ref por nosotros. Vue también proporciona una práctica función de utilidad llamada unwrap que es especialmente útil si nuestro valor podría ser un ref. Así que aquí tenemos dos variables, count, que es una variable reactiva creada con ref cero, y una variable local name que se asigna a la cadena Michael. Ahora importamos unwrap desde el paquete Vue y lo llamamos en nuestro count. Si bloqueamos el resultado, podemos ver que desenrolla correctamente el ref. Si ahora llamamos a unwrap en nuestra variable no reactiva name, también funciona y bloquea el resultado correcto.
7. Utilizando Refs y Reactivos en Vue.js
unwrap es una función de azúcar que verifica si una variable es un ref y llama a .value si lo es. Ref se puede usar con cualquier valor, pero los valores se acceden de manera diferente en el script y la plantilla. Los objetos Ref se pueden reasignar y pasar a través de funciones sin perder la reactividad. Mi preferencia es ref porque es más fácil identificar los valores reactivos. Agrupar refs dentro de un objeto reactivo es un patrón recomendado para una mejor organización y manejo más fácil.
Y eso funciona porque unwrap es una función de azúcar que verifica si la variable es un ref. Y si es un ref, devuelve, llama a count.value. De lo contrario, simplemente devuelve el valor en sí. Si estás usando VSCode y la extensión Volar, puedes habilitar que agregue automáticamente .value a los refs. Esta es una configuración que puedes habilitar. Se llama autocomplete-refs. Viene deshabilitado de forma predeterminada para reducir el uso de la CPU.
Y puedes ver en este ejemplo, si escribes, si ingresas el nombre count, la extensión automáticamente agrega .value después del nombre de la variable, lo cual puede ser muy útil.
Ahora hagamos una comparación entre reactive y ref. Ref puntúa ya que se puede usar con cualquier valor en comparación con reactive que solo se puede usar en tipos de objeto. Pero hay una desventaja al usar ref, y es que los valores se acceden de manera diferente en el script y la plantilla. Así que este es un punto a favor de reactive. Porque al usar ref dentro de la pestaña de script, necesitas llamar a .value. Pero Vue desenrolla automáticamente el ref en la plantilla, por lo que no necesitas llamar a .value allí. Los objetos Ref se pueden reasignar, lo cual es un punto a favor de ref. Ref también puntúa porque las referencias se pueden pasar a través de funciones sin perder la reactividad. También vimos que reactive pierde reactividad si intentamos desestructurar las propiedades del objeto en variables locales. Pero hay una ventaja al usar reactive si intentas migrar a la API de composición porque es similar al objeto de datos de Vue.
Lleguemos a la conclusión. En mi opinión, prefiero ref. Y lo que más me gusta de ref es que sabes que es un valor reactivo si ves que su propiedad se accede a través de .value. Y no es tan fácil si los objetos se crean con reactive. Entonces, si ves esta línea de código en tu aplicación, no sabes si algún objeto es un objeto JavaScript plano o si es un objeto reactivo. Si ves esta línea dentro de tu aplicación, es bastante probable que cualquier ref sea un ref y se comporte de manera reactiva.
Hablemos sobre un patrón recomendado y eso es agrupar refs dentro de un objeto reactivo. Entonces tenemos dos refs, loading y error, y los pasamos a un objeto reactivo que se asigna a una variable de estado local. Ahora podemos observar todo el objeto reactivo usando watch effect, pero también podemos definir watchers para los refs por separado. Y lo bueno de eso es que si actualizamos el ref, por ejemplo, estableciendo el valor de loading en false, esto activa ambos watchers. Y si no necesitas la reactividad del objeto de estado, también puedes agruparlo en un objeto JavaScript plano. Agrupar refs resulta en un solo objeto que es más fácil de manejar, mantiene tu código organizado y de un vistazo puedes ver que los refs agrupados pertenecen juntos y están relacionados de alguna manera.
8. Opiniones de la Comunidad de Vue
Las opiniones de la comunidad de Vue muestran que más del 60% prefiere usar ref, mientras que el 8% usa reactive y el 22% usa ambos. Michael Thiessen escribió un artículo detallado sobre ref versus reactive, resumiendo las opiniones de personas famosas de la comunidad de Vue. La recomendación es usar ref de forma predeterminada y reactive al agrupar variables. Tanto ref como reactive son herramientas poderosas en Vue 3, así que elige la que prefieras y mantén la consistencia en tu código.
Hablemos sobre las opiniones de la comunidad de Vue. Pregunté a mis seguidores de Twitter si están usando ref o reactive y más del 60% está usando ref, el 8% está usando reactive y el 22% está usando ambos, lo cual es bastante bueno. Puedes ver que ref es el ganador aquí. El increíble Michael Thiessen también escribió un brillante artículo detallado sobre ref versus reactive. Y recopiló las opiniones de personas famosas de la comunidad de Vue, como Eduardo, el creador de PNA, Daniel Roux, el líder del equipo de Nux, Matt de Learnvue y muchos más.
En resumen, todos ellos usan ref de forma predeterminada y reactive cuando necesitan agrupar cosas. Entonces, ¿deberías usar ref o reactive ahora? Mi recomendación es usar ref de forma predeterminada y reactive cuando necesites agrupar cosas. La comunidad de Vue tiene la misma opinión. Pero está totalmente bien si decides usar reactive de forma predeterminada. Ref y reactive son herramientas muy poderosas para crear variables reactivas en Vue 3. Puedes usar ambas sin ninguna limitación técnica. Simplemente elige la que te guste y trata de mantener la consistencia en cómo escribes tu código.
Gracias por escuchar y estoy feliz de responder tus preguntas. ♪♪♪
Comments