Reactividad y Gestión del Estado

Sistema Reactivo de Vue

Vue.js es conocido por su capacidad de manejar la reactividad de los datos de manera eficiente. Esto significa que cuando los datos cambian, la interfaz de usuario se actualiza automáticamente para reflejar esos cambios.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Sistema Reactivo en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <h1>Contador Reactivo</h1>
    <p>El contador es: {{ counter }}</p> <!-- Mostramos el valor del contador -->
    <button @click="incrementCounter">Incrementar</button> <!-- Botón para incrementar el contador -->
  </div>

  <script>
    const app = Vue.createApp({
      data() {
        return {
          counter: 0 // Inicializamos el contador en 0
        };
      },
      methods: {
        incrementCounter() {
          this.counter++; // Método para incrementar el contador
        }
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Reactividad en Vue.js

El sistema reactivo de Vue.js se basa en la capacidad de Vue de rastrear cambios en los datos y actualizar automáticamente el DOM para reflejar esos cambios. Vamos a desglosar cómo funciona esto en el ejemplo.

data

La opción data en la instancia de Vue define el estado inicial del componente. En este ejemplo, data devuelve un objeto que contiene una propiedad counter inicializada en 0.

				
					data() {
  return {
    counter: 0
  };
}

				
			

Interpolación

Utilizamos la interpolación {{ counter }} en el HTML para mostrar el valor actual de counter. Vue se encarga de actualizar esta parte del DOM cada vez que counter cambia.

				
					<p>El contador es: {{ counter }}</p>

				
			

Métodos

El objeto methods contiene funciones que pueden modificar el estado del componente. En este ejemplo, tenemos un método incrementCounter que incrementa el valor de counter.

				
					methods: {
  incrementCounter() {
    this.counter++;
  }
}

				
			

Manejo de Eventos

Utilizamos la directiva v-on (o el atajo @) para escuchar eventos del DOM y ejecutar métodos en respuesta. Aquí, estamos escuchando el evento click del botón y llamando al método incrementCounter cuando el botón es clicado.

				
					<button @click="incrementCounter">Incrementar</button>

				
			

¿Cómo Funciona la Reactividad?

  1. Inicialización de Datos: Cuando la instancia de Vue se crea, Vue convierte todas las propiedades del objeto data en propiedades reactivas utilizando Object.defineProperty. Esto permite que Vue «escuche» los cambios en estas propiedades.

  2. Renderización Inicial: Vue renderiza el DOM basándose en el estado inicial definido en data.

  3. Actualización Reactiva: Cuando el valor de counter cambia (por ejemplo, al llamar a this.counter++), Vue detecta el cambio y vuelve a renderizar la parte del DOM que depende de counter.

  4. Manejo de Eventos: Los eventos del DOM (como click) pueden ser manejados para cambiar el estado del componente. Estos cambios son automáticamente reflejados en la interfaz de usuario gracias al sistema reactivo de Vue.

Resumen

  • Reactividad de Datos: Vue convierte las propiedades de data en propiedades reactivas que actualizan automáticamente el DOM cuando cambian.
  • Interpolación: Utiliza {{ }} para mostrar datos reactivos en el HTML.
  • Métodos: Define funciones que pueden cambiar el estado del componente.
  • Manejo de Eventos: Utiliza v-on (o @) para escuchar eventos del DOM y ejecutar métodos en respuesta.

Data Binding

El data binding es una característica de Vue.js que nos permite enlazar datos de manera eficiente entre el modelo y la vista. Vue.js soporta tanto el one-way data binding (enlace de datos unidireccional) como el two-way data binding (enlace de datos bidireccional).

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Data Binding en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <h1>{{ title }}</h1> <!-- One-way data binding -->
    <p>{{ message }}</p> <!-- One-way data binding -->

    <input v-model="message" placeholder="Escribe algo"> <!-- Two-way data binding -->

    <p>Enlace de atributo: <span v-bind:title="tooltip">Pasa el ratón por aquí</span></p> <!-- One-way data binding con atributo -->
    
    <p>
      Enlace de clase: 
      <span :class="{'active': isActive}">Este texto tiene una clase activa</span>
    </p> <!-- One-way data binding con clase -->
    
    <button @click="toggleActive">Toggle Active</button> <!-- Botón para cambiar estado -->
  </div>

  <script>
    const app = Vue.createApp({
      data() {
        return {
          title: 'Data Binding en Vue.js', // Propiedad para one-way data binding
          message: '¡Hola, Vue.js!', // Propiedad para two-way data binding
          tooltip: 'Este es un tooltip', // Propiedad para v-bind
          isActive: false // Propiedad para v-bind:class
        };
      },
      methods: {
        toggleActive() {
          this.isActive = !this.isActive; // Método para alternar la clase activa
        }
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

One-way Data Binding

El one-way data binding permite mostrar datos del componente en la vista. Esto significa que cualquier cambio en el modelo de datos se refleja en la vista, pero no al revés.

  1. Interpolación: Utilizamos la sintaxis {{ }} para enlazar datos de manera unidireccional y mostrar valores en el HTML.

				
					<h1>{{ title }}</h1>
<p>{{ message }}</p>

				
			

2. Atributos HTML: Utilizamos v-bind (o su atajo :) para enlazar datos a atributos HTML.

				
					<p>Enlace de atributo: <span v-bind:title="tooltip">Pasa el ratón por aquí</span></p>

				
			

3. Clases: Utilizamos v-bind:class para enlazar datos a clases CSS dinámicamente.

				
					<p>
  Enlace de clase: 
  <span :class="{'active': isActive}">Este texto tiene una clase activa</span>
</p>

				
			

Two-way Data Binding

El two-way data binding permite sincronizar los datos entre el modelo y la vista. Esto significa que cualquier cambio en el input del usuario se refleja en el modelo de datos y viceversa.

  1. v-model: Utilizamos v-model para enlazar el valor de un input con una propiedad del componente.

				
					<input v-model="message" placeholder="Escribe algo">

				
			

Métodos

Los métodos nos permiten cambiar los datos en respuesta a eventos del usuario. En este ejemplo, utilizamos un método toggleActive para alternar el valor de isActive cuando se hace clic en un botón.

				
					methods: {
  toggleActive() {
    this.isActive = !this.isActive; // Método para alternar la clase activa
  }
}

				
			

Manejo de Eventos

Utilizamos la directiva v-on (o su atajo @) para escuchar eventos del DOM y ejecutar métodos en respuesta.

				
					<button @click="toggleActive">Toggle Active</button>

				
			

Resumen

  • One-way Data Binding: Utiliza {{ }} para interpolación y v-bind (o :) para enlazar atributos y clases de manera unidireccional. Esto refleja los cambios del modelo en la vista.
  • Two-way Data Binding: Utiliza v-model para sincronizar los datos entre el modelo y la vista, permitiendo que los cambios en los inputs del usuario se reflejen automáticamente en el modelo de datos.
  • Métodos: Define funciones para manejar la lógica y responder a eventos del usuario.
  • Manejo de Eventos: Utiliza v-on (o @) para escuchar eventos del DOM y ejecutar métodos en respuesta.

Watchers y computed properties

Estas herramientas nos permiten manejar y reaccionar a cambios en los datos de manera más eficiente y controlada.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Watchers y Computed Properties en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <h1>Computed Properties y Watchers</h1>
    
    <p>Nombre Completo (Computed): {{ fullName }}</p> <!-- Computed Property -->
    <input v-model="firstName" placeholder="Primer Nombre"> <!-- Two-way Data Binding -->
    <input v-model="lastName" placeholder="Apellido"> <!-- Two-way Data Binding -->

    <p>Contador: {{ counter }}</p>
    <button @click="incrementCounter">Incrementar</button>

    <p>Estado del Contador (Watched): {{ counterStatus }}</p> <!-- Watched Property -->
  </div>

  <script>
    const app = Vue.createApp({
      data() {
        return {
          firstName: '',
          lastName: '',
          counter: 0,
          counterStatus: ''
        };
      },
      computed: {
        fullName() {
          return `${this.firstName} ${this.lastName}`; // Concatenamos firstName y lastName
        }
      },
      watch: {
        counter(newValue, oldValue) {
          if (newValue > 10) {
            this.counterStatus = 'El contador es mayor que 10';
          } else {
            this.counterStatus = 'El contador es 10 o menos';
          }
        }
      },
      methods: {
        incrementCounter() {
          this.counter++;
        }
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Computed Properties

Las computed properties (propiedades calculadas) son propiedades que se calculan en función de otras propiedades. Son útiles cuando necesitamos realizar cálculos basados en los datos del componente y queremos que esos cálculos se actualicen automáticamente cuando los datos cambian. Las computed properties se almacenan en caché en función de sus dependencias reactivas y solo se vuelven a calcular cuando alguna de esas dependencias cambia.

  1. Definición de fullName:

    • En el ejemplo, fullName es una computed property que concatena firstName y lastName.
				
					computed: {
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

				
			

2. Uso de fullName:

  • fullName se utiliza en el HTML para mostrar el nombre completo del usuario, que se actualiza automáticamente cuando firstName o lastName cambian.
				
					<p>Nombre Completo (Computed): {{ fullName }}</p>

				
			

Watchers

Los watchers nos permiten observar y reaccionar a cambios en las propiedades reactivas de Vue.js. Son útiles cuando necesitamos ejecutar código en respuesta a cambios específicos en los datos.

  1. Definición de watcher para counter:

    • En el ejemplo, tenemos un watcher que observa la propiedad counter. Cada vez que counter cambia, el watcher se ejecuta y actualiza counterStatus en función del nuevo valor de counter.
				
					watch: {
  counter(newValue, oldValue) {
    if (newValue > 10) {
      this.counterStatus = 'El contador es mayor que 10';
    } else {
      this.counterStatus = 'El contador es 10 o menos';
    }
  }
}

				
			

2. Uso de counterStatus:

  • counterStatus se muestra en el HTML y se actualiza automáticamente en respuesta a los cambios en counter.
				
					<p>Estado del Contador (Watched): {{ counterStatus }}</p>

				
			

Métodos

Los métodos se utilizan para realizar acciones que modifican el estado del componente. En este ejemplo, el método incrementCounter incrementa el valor de counter cuando se hace clic en el botón.

				
					methods: {
  incrementCounter() {
    this.counter++;
  }
}
				
			

Resumen

  • Computed Properties: Son propiedades calculadas en función de otras propiedades y se almacenan en caché. Se vuelven a calcular solo cuando cambian sus dependencias reactivas.

    • Ejemplo: fullName que concatena firstName y lastName.
  • Watchers: Permiten observar y reaccionar a cambios en las propiedades reactivas. Se utilizan para ejecutar código en respuesta a cambios específicos.

    • Ejemplo: watch para counter que actualiza counterStatus.
  • Métodos: Definen acciones que modifican el estado del componente y pueden ser llamados desde el HTML en respuesta a eventos del usuario.

    • Ejemplo: incrementCounter que incrementa counter.

Introducción a Vuex

vamos a aprender sobre Vuex, la biblioteca oficial de manejo de estado para aplicaciones Vue.js. Vuex nos permite gestionar el estado de la aplicación de manera centralizada, facilitando la gestión de datos compartidos entre múltiples componentes.

¿Qué es Vuex?

Vuex es un patrón de estado y una biblioteca para aplicaciones Vue.js. Proporciona un almacén centralizado para todos los componentes de una aplicación, con reglas que aseguran que el estado solo pueda ser mutado de manera predecible.

Características de Vuex

  • Estado Centralizado: Todos los datos compartidos entre componentes se almacenan en un lugar centralizado.
  • Inmutabilidad del Estado: El estado solo puede ser mutado a través de mutaciones explícitas.
  • Acciones Asíncronas: Las acciones pueden realizar operaciones asíncronas y luego comprometer mutaciones.
  • Getters: Computed properties para el estado de Vuex.
  • Devtools Integración: Vuex se integra con las Vue Devtools para facilitar la depuración.

Instalación y Configuración de Vuex

Primero, necesitamos instalar Vuex en nuestro proyecto Vue.js. Puedes hacerlo ejecutando el siguiente comando:

				
					npm install vuex@next

				
			

Luego, configuramos Vuex en nuestro proyecto:

				
					// store.js
import { createStore } from 'vuex';

const store = createStore({
  state() {
    return {
      counter: 0
    };
  },
  mutations: {
    increment(state) {
      state.counter++;
    }
  },
  actions: {
    increment(context) {
      context.commit('increment');
    }
  },
  getters: {
    doubleCounter(state) {
      return state.counter * 2;
    }
  }
});

export default store;

				
			
				
					// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';

const app = createApp(App);
app.use(store); // Usamos Vuex en nuestra aplicación
app.mount('#app');

				
			
				
					<!-- App.vue -->
<template>
  <div id="app">
    <h1>Contador con Vuex</h1>
    <p>Contador: {{ counter }}</p> <!-- Accedemos al estado de Vuex -->
    <p>Contador Duplicado: {{ doubleCounter }}</p> <!-- Accedemos a un getter de Vuex -->
    <button @click="increment">Incrementar</button> <!-- Despachamos una acción de Vuex -->
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions } from 'vuex';

export default {
  computed: {
    ...mapState(['counter']), // Mapeamos el estado de Vuex a las propiedades del componente
    ...mapGetters(['doubleCounter']) // Mapeamos los getters de Vuex a las propiedades del componente
  },
  methods: {
    ...mapActions(['increment']) // Mapeamos las acciones de Vuex a los métodos del componente
  }
};
</script>

<style>
/* Estilos para la aplicación */
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
button {
  background-color: #42b983;
  border: none;
  padding: 10px 20px;
  color: white;
  cursor: pointer;
  border-radius: 5px;
}
button:hover {
  background-color: #38a77c;
}
</style>

				
			

Explicación

Estado (state)

El state es el objeto que contiene el estado compartido de la aplicación. En nuestro ejemplo, tenemos una propiedad counter que almacena el valor del contador. Definimos el estado inicial del contador en 0 en el archivo store.js.

Mutaciones (mutations)

Las mutaciones son funciones que cambian el estado de manera sincrónica. En nuestro ejemplo, tenemos una mutación llamada increment que incrementa el valor del contador. Las mutaciones aseguran que los cambios sean predecibles y rastreables.

Acciones (actions)

Las acciones son funciones que pueden ejecutar código asíncrono y luego comprometer mutaciones. En nuestro ejemplo, la acción increment despacha la mutación increment. Las acciones se utilizan para manejar lógica de negocio más compleja que puede involucrar operaciones asíncronas.

Getters (getters)

Los getters son funciones que derivan el estado de Vuex para obtener información calculada. En nuestro ejemplo, doubleCounter es un getter que devuelve el valor de counter multiplicado por dos. Los getters permiten realizar cálculos derivados del estado y pueden ser utilizados como propiedades computadas en los componentes.

Mapeo en Componentes

En el archivo App.vue, utilizamos los helpers mapState, mapGetters, y mapActions para mapear el estado, los getters y las acciones de Vuex a las propiedades y métodos del componente. Esto nos permite acceder y manipular el estado de Vuex directamente desde los componentes.

  • mapState: Mapea el estado de Vuex a las propiedades del componente.
  • mapGetters: Mapea los getters de Vuex a las propiedades del componente.
  • mapActions: Mapea las acciones de Vuex a los métodos del componente.

Resumen

  • Estado (state): Almacena los datos compartidos de la aplicación.
  • Mutaciones (mutations): Funciones que cambian el estado de manera sincrónica.
  • Acciones (actions): Funciones que pueden ejecutar código asíncrono y luego comprometer mutaciones.
  • Getters (getters): Computed properties para el estado de Vuex.
  • Mapeo en Componentes: Utiliza mapState, mapGetters, y mapActions para conectar el estado de Vuex con los componentes de Vue.