Integrar un state management sólido marca la diferencia en la experiencia de usuario. Aquí verás cómo se implementa Viewex en Platzi Music, cómo reemplazar el event bus por un store centralizado y cómo optimizar llamadas a la API con actions, mutations y getters, además del uso del spread operator para mapState, mapActions y mapGetters.
¿Cómo instalar Viewex y configurar Bubble para usar spread operator?
Para iniciar, se instalan las dependencias y se configura el preset necesario para habilitar el spread operator.
Instalar Viewex con NPM.
npm i -S viewex
Instalar el preset de Bubble para spread operator.
npm i -D bubble-preset-stage-2
Agregar el preset en el archivo Bubble RC en la línea posterior a environment. Combina presets si ya existe otro.
Cada cambio en webpack o Bubble requiere detener y relanzar el proceso de desarrollo.
npm run dev
Esta base habilita el uso de mapState, mapActions y mapGetters con el spread operator y prepara el proyecto para el store centralizado.
¿Cómo crear el store y reemplazar el event bus?
El objetivo es centralizar el flujo de datos y evitar la complejidad de comunicar componentes por props y eventos.
Crear el archivo store.js dentro de source.
Registrar el plugin y crear la instancia del store.
importVuefrom'vue'importViewexfrom'viewex'Vue.use(Viewex)exportconst store =newViewex.Store({state:{track:{}},mutations:{setTrack(state, track){ state.track= track
}}})
Importar el store en main.js e inyectarlo en la instancia de Vue junto al router.
Con esto, se elimina el event bus y se usa this.$store.commit('setTrack', track) para actualizar el estado. Las mutations permiten rastrear cambios, depurar y volver a estados previos.
¿Cómo vincular el player con mapState y computed?
El Player Component deja de manejar data local y escucha el estado global.
Importar mapState desde Viewex.
Usar computed con mapState y el spread operator para enlazar track.
Flujo recomendado: la action obtiene la respuesta, hace commit a la mutation y esta actualiza el state.
¿Cómo decidir entre usar el store o llamar a la API?
En Track Detail se combinan mapState y mapActions. Si vienes desde search, el track ya está en memoria. Si recargas la página o entras directo por URL, se llama a la API.
import{ mapState, mapActions }from'viewex'exportdefault{computed:{...mapState(['track'])},methods:{...mapActions(['getTrackByID'])},created(){const id =this.$route.params.idconst noTrack =!this.track||!this.track.idconst different =this.track&&this.track.id!== id
if(noTrack || different){this.getTrackByID({ id }).then(()=>{console.log('track loaded')})}}}
Resultado: navegación inmediata cuando la data ya existe en el store y solicitud a la API solo cuando es necesario. Se evita latencia y carga duplicada.
¿Cómo prevenir errores por objetos vacíos en la vista?
Controlar render con v-if hasta tener track.id para no acceder a propiedades inexistentes.
<divv-if="track && track.id"><!-- contenido que usa track --></div>
Manejar estados iniciales vacíos antes de acceder a estructuras anidadas.
¿Cómo crear un getter útil y usarlo en la interfaz?
Un getter permite derivar datos del estado sin duplicarlos. Ejemplo: mostrar título con artista.
Recalcula de forma reactiva cuando cambia el estado.
Evita errores cuando el objeto aún no existe.
¿Qué más considerar a escala?
Viewex soporta módulos para dividir el store por dominio como track, users o albums, y luego centralizarlos. Útil en aplicaciones grandes.
Se mencionan conceptos clave: estado centralizado, patrón de flags, mutations, actions, getters y computed trabajando juntos para un flujo consistente entre componentes.
¿Tienes dudas o quieres compartir cómo aplicaste estas ideas en tu proyecto? Escribe tus preguntas o comentarios y conversemos.
Hay otro caso dentro de la aplicación en el que lo podemos usar para tener mejor rendimiento: cuando se hace una búsqueda y se hace clic para ver el detalle de una canción (clic directamente en 🌎), el objeto track o está vacío o tiene información de una canción anterior, por lo cual el componente TrackDetail hará el llamado a la API.
Lo que se puede hacer es almacenar la información del nuevo track antes de ir a la vista de detalle desde el componente Track cambiando un poco el método goToTrack, así:
El parámetro de la función goToTrack no es sólo el id, sino el objeto entero
Les recomiendo que para añadir Vuex lo hagan mediante el comando: vue add vuex que justamente se encargará de añadir y hacer todas las configuraciones necesarias al proyecto:D!
Buen aporte, no se si quedaria mejor o peor pero el uso de una ternary es bienvenido siempre que se mantenga un codigo limpio. En mi caso me gusta el patron de early return pero ambas son buenas opciones.
Encontré un error… si buscas una canción luego seleccionas los detalles … y de los detalles vas a “nosotros” carga la url pero no el contenido
buscar>>detalles>>de detalles a notros>>>no hay cambios pero si cambia la url
Gracias RetaxMaster, pero no creo que sea de eso, mira que los módulos son de paquetes del core de JavaScript y fallan en archivos que funcionaban antes de la instalación de redux. Además al intentar instalarlos sale un error de npm.
Muchas gracias.
Digamos que es un poco al revés. El Stage 2 incluye algunas propuestas que aún no están muy cerca de ser estándar. El Stage 3 son las propuestas que ya casi son estándar. Puedes usar el Stage 3 sin necesidad de instalar el Stage 2. Pero no puedes usar el Stage 2 sin instalar también el Stage 3. :wink:
Hola! No he usado Vuex, pero supongo que funciona igual que Redux en React, y sí, cuando se recarga la página se borra todo porque la aplicación comienza a iniciar desde su estado inicial, para que estos se mantenga debes tener alguna forma de persistir el estado global. Esto puede ser usando localstorage para algo muy simple, o el estado puede venir desde el server side rendering o también puedes hacer fetch a una API que tengas y que almacene esto en un base de datos.
Hola, es una buena pregunta. Creo que es algo que podria considerarse, habria que evaluar cuantas canciones son y que tan seguido se puede repetir el escenario que planteas para ver si conviene almacenar esa X cantidad de canciones en memoria. Tene en cuenta tambien que el browser chachea los HTTP request por lo cual tambien hay cierta optimizacion en caso de busqueda repetida. En resumen creo que puede ser algo bueno a considerar pero siempre teniendo en cuenta cada caso. Muy buen aporte!
Algo raro sucede con el componente search y la directiva
blur personalizada.
Mi caso es éste:
La línea a.removeAttibute('disabled') en blur.js me da el
siguiente error:
TypeError: a.removeAttibute is not a function
Comento esa línea y luego procedo a hacer búsquedas,
y sucede lo siguiente:
Cargo la aplicación y busco 'woman'
Me aparecen algunas canciones, algunas con blur y otras normales.
Hago otra búsqueda con la palabra 'time' y me aparecen otras
canciones pero ésta vez el blur aparece en las mismas posiciones
de las canciones con blur de la primera búsqueda
Abro de nuevo la aplicación y busco 'time' y me aparecen algunas
canciones, ninguna sin blur
Busco cualquier otra canción y no importa si tienen o no preview_url,
no se aplica el blur
El proyecto lo estoy trabajando en un repositorio de git local.
He regresado al commit donde se crea la directiva blur.js y me
sucede lo mismo
Me sucedió lo mismo, el problema es que Vue no estaba olvidando las card marcadas en Blur entre una búsqueda y otra búsqueda y marcaba como blur las nuevas sin olvidar las ya marcadas, luego de varias búsquedas casi todas eran blur jejejeje.
Mi solución fue simple: Agregar la directiva :key sobre el pm-track component, de ésta forma Vue vería la actualización de resultados.
No se si alguien se haya dado cuenta, pero cuando se integro Vuex al proyecto dejo de funcionar el estilo de bordeado color verde al Track en la UI al seleccionarla?
Saludos
Si te sirve aun ya resolví el problema. Y es que uno de los eventos emitidos por el componente (select) se encarga precisamente de esos estilos, y curiosamente en el video los borraron
Archivo Mixins/track.js
/*
Los mixin permite compartir funcionalidad entre componentes.
Esto hace que se reutilice el código.
Para este ejemplo el método selectTrack() se invoca desde el componente track y desde
el trackDetail. ambos hacen lo mismo, vincular la data al componente Player.
Podemos tener funcionalidad compartida de muchos lados.
*/const trackMixin ={// Se define cualquier funcinalidad del Vue Model// cualquier cosa que soporte un componentemethods:{selectTrack(){// if (!this.track.preview_url) { return }// Los hijos pasan información al padre a través de eventosthis.$emit('select',this.track.id)// En este caso se usa el plugin ya que esta info va a otro componente sin parentesco// this.$bus.$emit('set-track', this.track)// confirmar una mutación para que modifique el estado global de la aplicaciónthis.$store.commit('setTrack',this.track)}}}exportdefault trackMixin
Hola!
A alguien le habrá aparecido un error en la consola como éste:
[Vue warn]:Errorin directive blur bind hook:"TypeError: a.removeAttibute is not a function"found in---><App> at src/components/Search.vue<App> at src/App.vue<Root>
Es sencillo. En tu archivo Search.vue, seguramente, tendras un objeto, que recibas por parametro o que tu mismo definas, que tiene el metodo removeAttibute y que simplemente el error dice que no es una función.
Asegurate que exista y/o este bien declarada.
¿Si quisiera por ejemplo, guardar datos básicos del usuario que inició sesión dentro de mi app, sería válido utilizar Vuex? Lo digo, porque a veces es diferentes vistas es necesario mostrar su nombre, apellidos, edad, etc. Entonces para no reescribir el código en cada vista ( o sea, hacer una función en cada component) utilizar el vuex.
Si, uno de los objetivos de los estados es compartir información entre componentes y poder dispara eventos cuando algo cambia en el estado, puedes tener información almacenada en el estado o tenerla también en local storage.