Métodos, calculados y observadores en Vue.js | Programar Plus

Una de las razones por las que me encanta trabajar con Vue es por lo útil que es methods, computed, y watchers son, y la legibilidad de su distinción. Hasta que comprenda los tres, es difícil aprovechar la funcionalidad de Vue en todo su potencial. Aún así, la mayoría de las personas que veo confundidas acerca de este marco también tienden a estar confundidas acerca de las diferencias aquí, así que profundicemos.

En caso de que necesite una respuesta rápida y no tenga tiempo para leer todo el artículo, aquí hay un pequeño TL; DR:

  • Métodos: Estos son exactamente lo que parecen (¡sí, nombrar!). Son funciones que cuelgan de un objeto, por lo general, la propia instancia de Vue o un componente de Vue.
  • Computado: Estas propiedades pueden parecer a primera vista que se usarían como un método, pero no lo son. En Vue, usamos data para realizar un seguimiento de los cambios en una propiedad en particular que nos gustaría que fuera reactivo. Las propiedades calculadas nos permiten definir una propiedad que se usa de la misma manera que data, pero también puede tener alguna lógica personalizada que se almacena en caché en función de sus dependencias. Puede considerar las propiedades calculadas como otra vista de sus datos.
  • Vigilantes: Estos le permiten echar un vistazo al sistema de reactividad. Se nos ofrecen algunos ganchos con los que observar las propiedades almacenadas por Vue. Si queremos agregar un poco de funcionalidad cada vez que algo cambia, o responder a un cambio en particular, podemos observar una propiedad y aplicar algo de lógica. Esto significa que el nombre del observador debe coincidir con lo que estamos tratando de observar.

Si algo de esto suena confuso, ¡no se preocupe! Profundizaremos más abajo y, con suerte, abordaremos cualquier confusión. Si ya está familiarizado con JavaScript vanilla, los métodos pueden resultarle bastante obvios, además de una o dos advertencias. Entonces puede que te convenga (me encanta esa frase) pasar a las secciones Computadoras y Vigilantes.

Métodos

Es probable que los métodos sean algo que usará mucho mientras trabaja con Vue. Tienen un nombre adecuado porque, en esencia, estamos colgando una función de un objeto. Son increíblemente útiles para conectar la funcionalidad a las directivas de eventos, o incluso simplemente para crear un poco de lógica para reutilizarla como cualquier otra función. Puede llamar a un método dentro de otro método, por ejemplo. También puede llamar a un método dentro de un enlace de ciclo de vida. Son muy versátiles.

Aquí hay una demostración simple para demostrar:

Vea el ejemplo de métodos Pen Slim de Sarah Drasner (@sdras) en CodePen.

<code class="language-css"><div id="app">
  <button @click="tryme">Try Me</button>
  <p>{{ message }}</p>
</div>
new Vue({
  el: '#app',
  data() {
    return {
      message: null
    }
  },
  methods: {
    tryme() {
      this.message = Date()
    }
  }
})

También podríamos haber ejecutado la lógica en la propia directiva como <button @click="message = Date()">Try Me</button>, que funciona muy bien para este pequeño ejemplo. Sin embargo, a medida que crece la complejidad de nuestra aplicación, es más común hacer lo que vemos arriba para dividirla y mantenerla legible. También hay un límite para la lógica que Vue le permitirá expresar en una directiva; por ejemplo, las expresiones están permitidas pero las declaraciones no.

Puede notar que podemos acceder a este método dentro de ese componente o instancia de Vue, y podemos llamar a cualquier parte de nuestros datos aquí, en este caso, this.message. No tiene que llamar a un método como llamaría a una función dentro de una directiva. Por ejemplo, @click=”methodName()” es innecesario. Puedes referenciarlo con @click=”methodName”, a menos que necesite pasar un parámetro, como @click=”methodName(param)”.

Usar directivas para llamar a métodos también es bueno porque tenemos algunos modificadores existentes. Un ejemplo que es muy útil es .prevent, que evitará que un evento de envío vuelva a cargar la página, que se usa así:

<form v-on:submit.prevent="onSubmit"></form>

Hay muchos más, aquí hay algunos.

Computado

Las propiedades calculadas son muy valiosas para manipular datos que ya existen. Siempre que esté creando algo en el que necesite clasificar un gran grupo de datos y no desee volver a ejecutar esos cálculos con cada pulsación de tecla, piense en utilizar un valor calculado.

Algunos buenos candidatos incluyen, entre otros:

  • Actualizar una gran cantidad de información mientras un usuario escribe, como filtrar una lista
  • Recopilación de información de su tienda Vuex
  • Validación de formularios
  • Visualizaciones de datos que cambian según lo que el usuario necesita ver

Las propiedades calculadas son una parte vital de Vue para comprender. Son cálculos que se almacenarán en caché en función de sus dependencias y solo se actualizarán cuando sea necesario. Son extremadamente eficaces cuando se usan bien y son extraordinariamente útiles. Hay muchas bibliotecas grandes que manejan este tipo de lógica que ahora puede eliminar con solo unas pocas líneas de código.

Las propiedades calculadas no se usan como métodos, aunque al principio, pueden parecer similares: está indicando algo de lógica en una función y regresa, pero el nombre de esa función se convierte en una propiedad que luego usaría en su aplicación como data.

Si necesitáramos filtrar esta gran lista de nombres de héroes según lo que el usuario estaba escribiendo, así es como lo haríamos. Mantendremos esto realmente simple para que pueda entender los conceptos básicos. Originalmente, nuestra lista saldría en nuestra plantilla usando names, que almacenamos en data:

new Vue({
  el: '#app',
  data() {
    return {
      names: [
        'Evan You',
        'John Lindquist',
        'Jen Looper',
        'Miriam Suzanne',
        ...
      ]
    }
  }
})
<div id="app">
  <h1>Heroes</h1>
  <ul>
    <li v-for="name in names">
      {{ name }}
    </li>
  </ul>
</div>

Ahora creemos un filtro para esos nombres. Comenzaremos creando una entrada con v-model que originalmente será una cadena vacía, pero eventualmente usaremos para hacer coincidir y filtrar nuestra lista. Llamaremos a esta propiedad findName y puede verlo referenciado tanto en la entrada como en el data.

<label for="filtername">Find your hero:</label>
<input v-model="findName" id="filtername" type="text" />
data() {
  return {
    findName: '',
    names: [
      'Evan You',
      'John Lindquist',
      ...
    ]
  }
}

Ahora, podemos crear el propiedad calculada que filtrará todos los nombres en función de lo que el usuario haya escrito en la entrada, por lo que cualquier cosa en nuestro findName propiedad. Notarás que estoy usando expresiones regulares aquí para asegurarme de que las mayúsculas no coincidan no importan, ya que los usuarios normalmente no usarán mayúsculas mientras escriben.

computed: {
  filteredNames() {
    let filter = new RegExp(this.findName, 'i')
    return this.names.filter(el => el.match(filter))
  }
}

Y ahora actualizaremos lo que estamos usando en la plantilla para generar esto:

<ul>
  <li v-for="name in names">
    {{ name }}
  </li>
</ul>

…a esto:

<ul>
  <li v-for="name in filteredNames">
    {{ name }}
  </li>
</ul>

¡Y nos filtra con cada pulsación de tecla! Solo tuvimos que agregar un par de líneas de código para que esto funcione, y no tuvimos que cargar bibliotecas adicionales.

Vea la lista de filtros de lápiz con Computed-end de Sarah Drasner (@sdras) en CodePen.

No puedo decirte cuánto tiempo ahorro usándolos. Si está utilizando Vue y aún no los ha explorado, hágalo, se lo agradecerá.

Vigilantes

Vue tiene bonitas abstracciones, y cualquiera que haya sido programador durante un tiempo normalmente le dirá que las abstracciones pueden ser un fastidio porque eventualmente llegará a un caso de uso que no pueden resolver. Sin embargo, esta situación se tiene en cuenta, porque Vue nos otorga un acceso más profundo al sistema de reactividad, que podemos aprovechar como ganchos para observar cualquier cambio. Esto puede ser increíblemente útil porque, como desarrolladores de aplicaciones, la mayor parte de lo que somos responsables son cosas que cambian.

Los observadores también nos permiten escribir código mucho más declarativo. Ya no estás rastreando todo tú mismo. Vue ya lo está haciendo bajo el capó, por lo que también puede tener acceso a los cambios realizados en las propiedades que está rastreando, en data, computed, o props, por ejemplo.

Los observadores son increíblemente buenos para ejecutar la lógica que se aplica a otra cosa cuando se produce un cambio en una propiedad (escuché por primera vez esta forma de decirlo de Chris Fritz, pero dice que también podría haberlo escuchado de otra persona ☺️). Esta no es una regla estricta; absolutamente puede usar observadores para la lógica que se refiere a la propiedad en sí, pero es una buena manera de ver cómo los observadores son inmediatamente diferentes de las propiedades calculadas, donde el cambio será en referencia a la propiedad que tiene la intención de usar.

Repasemos el ejemplo más simple posible para que tenga una idea de lo que está sucediendo aquí.

Su navegador no soporta la etiqueta de vídeo.

new Vue({
  el: '#app', 
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter() {
      console.log('The counter has changed!')
    }
  }
})

Como puede ver en el código anterior, estamos almacenando counter en data, y usando el nombre de la propiedad como el nombre de la función, podemos verlo. Cuando hacemos referencia a eso counter en watch, podemos observar cualquier cambio en esa propiedad.

Estado de transición con vigilantes

Si el estado es lo suficientemente similar, incluso puede simplemente hacer la transición del estado con observadores. Aquí hay un ejemplo que construí desde cero de un gráfico con Vue. A medida que cambian los datos, los observadores los actualizarán y simplemente realizarán la transición entre ellos.

SVG también es bueno para una tarea como esta porque está construido con matemáticas.

Consulte el gráfico de lápiz creado con Vue, estado de transición por Sarah Drasner (@sdras) en CodePen.

watch: {
  selected: function(newValue, oldValue) {

    var tweenedData = {}

    var update = function () {
      let obj = Object.values(tweenedData);
      obj.pop();
      this.targetVal = obj;
    }

    var tweenSourceData = { onUpdate: update, onUpdateScope: this }

    for (let i = 0; i < oldValue.length; i++) {
      let key = i.toString()
      tweenedData[key] = oldValue[i]
      tweenSourceData[key] = newValue[i]
    }

    TweenMax.to(tweenedData, 1, tweenSourceData)
  }
}

¿Que pasó aquí?

  • Primero creamos un objeto ficticio que será actualizado por nuestra biblioteca de animación.
  • Entonces tenemos un update función que se invoca en cada paso de interpolación. Usamos esto para impulsar los datos.
  • Luego creamos un objeto para contener los datos de origen que se van a interpolar y el puntero de función para los eventos de actualización.
  • Creamos un bucle for y convertimos el índice actual en una cadena
  • Entonces podemos interpolar sobre nuestro objeto ficticio de destino, pero solo haremos esto para la clave específica

También podríamos usar la animación en los observadores para crear algo como este dial de diferencia horaria. Viajo un poco y todos mis compañeros de trabajo están en diferentes áreas, por lo que quería una forma de rastrear en qué hora local estábamos todos, así como también alguna significación del cambio de día / noche.

Consulte la comparación de tiempos de Pen Vue de Sarah Drasner (@sdras) en CodePen.

Aquí estamos viendo la propiedad marcada, y dispararemos diferentes métodos que contienen animaciones de línea de tiempo que cambian el tono y la saturación y algunos otros elementos basados ​​en la asociación relativa a la hora actual. Como se mencionó anteriormente, el cambio ocurre en el menú desplegable, pero lo que estamos ejecutando es la lógica que se aplica en otros lugares.

watch: {
  checked() {
    let period = this.timeVal.slice(-2),
      hr = this.timeVal.slice(0, this.timeVal.indexOf(':'));

    const dayhr = 12,
      rpos = 115,
      rneg = -118;

    if ((period === 'AM' && hr != 12) || (period === 'PM' && hr == 12)) {
      this.spin(`${rneg - (rneg / dayhr) * hr}`)
      this.animTime(1 - hr / dayhr, period)
    } else {
      this.spin(`${(rpos / dayhr) * hr}`)
      this.animTime(hr / dayhr, period)
    }

  }
},

También hay una serie de otras cosas interesantes sobre los observadores, por ejemplo: tenemos acceso a las versiones nueva y antigua de la propiedad como parámetros, podemos especificar deep si queremos ver un objeto anidado. Para obtener información más detallada, hay mucha buena información en la guía.

Puede ver cómo los observadores pueden ser increíblemente útiles para cualquier cosa que se esté actualizando, ya sean entradas de formulario, actualizaciones asincrónicas o animaciones. Si tiene curiosidad por saber cómo funciona la reactividad en Vue, esta parte de la guía es realmente útil. Si desea saber más sobre la reactividad en general, disfruté mucho la publicación de Andre Staltz y la sección Reactividad de A Better Way to Code de Mike Bostock.

Terminando

Espero que este sea un desglose útil sobre cómo usar cada uno y acelere el proceso de desarrollo de su aplicación al usar Vue de manera eficiente. Existe una estadística de que pasamos el 70% de nuestro tiempo como programadores leyendo código y el 30% escribiéndolo. Personalmente, me encanta que, como mantenedor, pueda mirar una base de código que nunca antes había visto y saber de inmediato qué pretendía el autor con la distinción hecha de methods, computed, y watchers.