Creación de Layouts con Vue y Bootstrap para Mejorar la UI
Aunque la app se ve mejor sigue estando la falta de estilo, ya que se ve todo alineado a la izquierda.
Para arreglar esto vamos a hacer uso de las clases CSS de Bootstrap y a crear un Layout. Con los layouts conseguimos reutilizar código o componentes que se utilizan en todas las páginas, implementándolo una sola vez.
Creamos, dentro de la carpeta /layouts un archivo con el nombre MainLayout.vue
Todas nuestras vistas que hagan match a una ruta se van a inyectar dentro de esta etiqueta, <router-view />.
Por lo tanto, en el layout principal podemos poner componentes como la barra de navegación (Navbar) o el footer, que van a ser iguales para todas las páginas.
Lo más probable es que dichos componentes no cambien entre páginas, por lo que es perfecto que estén aquí.
Los componentes de tipo layout (recuerda, en Vue todo son componentes), son útiles cuando queremos tener varios tipos de páginas, por ejemplo, podemos tener un layout específico para la página del Login, otro para las páginas de error y otro layout para el resto de páginas.
En este curso vamos a crear 2 layouts distintos, uno para el loading y otro para el resto de páginas.
Debes crear los layouts según las necesidades de tu proyecto.
Ya tenemos el layout principal de nuestra app. Vamos a crear el layout de Loading, y para ello tenemos que crear otro componente dentro de la carpeta /layouts, con el nombre LoadLayout.vue y le dotamos del siguiente contenido:
> 📗 Un Slot en Vue es una funcionalidad inspirada en la especificación de Web Components con la finalidad de poder definir zonas de contenido distribuido. Puede contener cualquier plantilla de código, incluyendo HTML.
> Lee más acerca de los slots de Vue aquí: https://es.vuejs.org/v2/guide/components-slots.html
Bien, ya tenemos nuestro componente Loading, nuestro MainLayout y nuestro LoadingLayout, pero nos sigue faltando un elemento. ¿Cómo controlamos si debemos mostrar el layout de Loading o el layout principal?
Vamos a crear una variable en nuestro Store que nos indique el estado de nuestra app, es decir, si está loading o no.
Esto lo vamos a usar durante la petición del token de autenticación, es decir, mientras hacemos la llamada HTTP estaremos mostrando el LoadingLayout con el componente Loading.
Por lo tanto, vamos a nuestra carpeta de /store/modules y creamos un nuevo módulo (archivo) llamado loading.js, que es el que va a gestionar el estado Loading inicial de nuestra app.
No olvidemos que esto es solo una práctica y lo más probable es que hacer esto en un proyecto pequeño (como este) no tenga sentido.
Hemos creado una variable (estado) isLoading con un espacio de nombres y una función (mutación) que cambia el valor de isLoading. Extremadamente sencillo, pero vamos a ver como trabajar con módulos y namespaces con Vuex.
Ahora sí, tenemos todos los ingredientes necesarios para crear nuestro Loading mientras se hace la petición POST para obtener el token.
Por defecto, isLoading tiene valor false, por lo tanto, el primer paso es cambiarlo a true cuando estemos haciendo la petición de token.
Esto lo hacemos desde nuestro módulo oauth.js del Store, en nuestra función (acción) getToken.
Mientras dure la llamada HTTP ponemos el valor a true y cuando termine (con error o con éxito) lo ponemos a false.
Lo bueno de tener namespaces con Vuex, aparte de modularizar por funcionalidad, es que no tendremos problemas con el nombrado de nuestras acciones y mutaciones porque llevan el prefijo del módulo, en este caso loading/XXX.
Ahora sí, ya tenemos todo listo para ir a nuestro fichero App.vue y decirle que mientras este esperando al token muestre el loading, y que cuando termine, muestre el layout principal, que contiene las vistas.
Aprovechamos para borrar los enlaces que venían por defecto. Nuestro fichero App.vue, en el bloque de template, es decir el HTML, se vería así:
Desde Vuex nos traemos la funcionalidad de mapState
Importamos los 3 componentes que necesitamos (los 2 layouts que acabamos de crear y el componente de Loading)
A través de mapState podemos acceder a los valores del estado de nuestro módulo (en este caso nos interesa el módulo de loading) y utilizarlos en nuestro componente.
Para usar mapState con namespaces lo único que tenemos que hacer es indicarle, antes de empezar a mapear el estado, a qué módulo nos referimos, es decir, 'loading'. El nombre del módulo se corresponde con el nombre del fichero.
Como el módulo se llama loading.js tendremos que usar de nombre loading (sin la extensión). Con esto le decimos que solo nos interesa el estado del loading.
Con las directivas v-if y v-else mostramos un componente u otro según esté cargando o no. Si está loading mostramos loading, en caso contrario mostramos la vista.
En el navegador, abrimos las Herramientas para desarrolladores (o DevTools), vamos a la pestaña de console y recargamos la app. Deberías ver el siguiente error:
¿Adivinas por qué es? Efectivamente, no hemos dado de alta el módulo en nuestro Store. Vamos a ello. Desde el fichero de /store/index.js agregamos lo siguiente:
Si vas al navegador deberías ver, si no hay ningún error, el componente Loading durante un pequeño espacio de tiempo y que después se carga la vista de la página Home
Hola, sólo quería hacer un alance al código. El profesor puso este código en la parte del script, por alguna razón no tomo los estilos css y quedo oculto bajo los comentarios:
de todas formas ambos códigos funcionan, el cambio es que acá ocupa la función mapState de vuex
Hola, hasta ahora todo genial. Solo me preguntaba si hay alguna razon particular por la cual usamos mayusculas para algunos metodos por ejemplo: SET_LOADING, SET_ACCESS_TOKEN, SET_LOADING ?
Son metodos reservados o es solo un estandar o buena practica?
Muchas gracias de antemano.
Es un estándar de la industria hacerlo en mayúscula, pero puedes ponerle el nombre que quieras, incluso en minúscula y te va a funcionar igual. 👏
Hola, pero por que son específicamente esos métodos los que van en mayusculas? Quedo atento
Perfecto, aunque tengo dos cuantas dudas:
1.- Tengo entendido que por buenas prácticas (Y esto se menciona en los cursos anteriores), el v-if solo se debe usar en componentes que vamos a renderizar una sola ves, en este caso, ocuparemos el loader en diferentes ocasiones, por lo que usar v-if podría consumir más recursos de los esperado, ¿No sería mejor usar v-show? Así solamente mostramos el loading cuando lo necesitemos y cuando no solo se oculta con CSS (v-show), así no estamos rendereando una y otra vez el loader, aunque claro, esto igual puede dar problemas, porque si en el layout principal usamos propiedades que no están disponibles aún, al usar v-show dará un error, pero con v-if no habrá problema
2.- Ya que el loader lo usaremos mucho, ¿No sería más práctico importarlo como un componente global? Algo así como Bootstrap-vue que no necesitamos importarlo en cada componente que usemos?
Puede ser una buena idea crear un componente base con el Loader, si
Muy guay el tema de los namespaces de Vuex!!
Cuando el código empieza a crecer, se vuelven interesantes ;D
¿Que significa el {root:true} dentro de commit('loading/SET_LOADING', true, { root: true })?
Es necesario ponerlo cuando, en Vuex, estás usando módulos con namespace: true.
Para más información, revisa estos 2 enlaces:
Si en el módulo de oauth.js no tuviéramos namespace: true, podrías hacer el commit de la siguiente forma:
!commit
Buena pregunta Omar, seguro que hay más estudiantes que lo consideran importante. Gracias. Ahí te dejé la explicación.
Mi duda es por que en la parte de las actions de oauth.js, se coloca la propiedad de root: true? A que se refiere esto. Quedo atento
En resumen, es para que puedas actions en modo root dentro de un “namespaced module”
hasta el momento habia entendido todo, pero lo del <router-view/> me tiene confundido, como es que se carga la vista home si en ningun momenlo lo enlazamos?
¡Hola! La carga la ahce automáticamente Vue, es decir, nosotros en la clase 4 agregamos el router (mira la sección de rutas).
Entonces, Vue ya sabe que tiene un router agregado, por lo que cuando ve la etiqueta <router-view> Vue mira cuál URL se está cargando y automáticamente hace el match con la ruta que esté en tu archivo de routes.js y una vez que hace match inserta el componente correspondiente ahí en donde estaba esa etiqueta <router-view> :D
Como explica RetaxMaster, esa etiqueta se encarga de todo. Tu configuras tus rutas en tu archivo de rutas, y cuando uses <router-view> el framework hace todo por ti y se encarga de manejar las vistas
Como pequeño aporte me gustaría añadir que a_ mapState_ también es posible enviarle como segundo paramétro un Array de elementos con los estados que queremos traernos, que a mí personalmente, me gusta más como queda:
Ambas opciones son válidas, usando la forma de objeto puedes cambiarle el nombre a nivel local, sin embargo con el formato array te lo traes con el nombre que tenga.
¿Cómo vas, ya lo terminaste? :DD
Hola, estuve copiando y probando el código, salió todo ok. Pero a veces en la consola me daba error de identacion o falta linea de espacio al final de cada archivo. Hay alguna manera de solucionarlo sin estar yendo linea por linea? Ejemplo de errores:
23:1 error Expected indentation of 6 spaces but found 8 indent
47:2 error Newline required at end of file but not found eol-last
Eso es el linter en acción. De esta forma todo el código que escribas (tanto si trabajas solo, como si estas en un equipo con más gente) va a estar con el mismo estilo. En mi IDE yo tengo un comando que me permite ajustar mi código según el linter que esté usando.
Para arreglar algunos avisos del linter puedes usar esto: npm run lint --fix
¿Te funcionó?
Compañeros, leí la documentacion de Vuex pero la verdad no me queda muy claro como funciona el el spread operator en el mapState(), Gracias!
:P
Te respondo luego, que estoy desde el móvil y es largo de escribir