Pasar props desde +layout a una página con `stores` y `parent()` en SvelteKit
Atención: este artículo ha sido actualizado para tener en cuenta los cambios importantes en la API de SvelteKit a partir de su versión @sveltejs/[email protected]
y [email protected]
.
Anteriormente se usaba la función load
dentro de una etiqueta <script context="module">
, y la prop stuff
de SvelteKit. Esto ha cambiado.
Los Layouts en SvelteKit son plantillas que añaden elementos a todas las páginas que estén en ese mismo nivel y los siguientes.
Así, por ejemplo, te evitas tener que añadir un Header
o un Footer
en cada ruta, con solo agregarlo una vez en el archivo /src/routes/+layout.svelte
.
Como vimos al añadir transiciones entre páginas, el +layout
puede servir para mucho más.
Vamos a ver un ejemplo donde pasamos data desde el +layout
a todas las rutas en SvelteKit, para intercambiar info entre una y otra.
En este caso vamos a ver un supuesto donde queremos:
- Detectar parámetros de URL lo antes posible (
+layout
es perfecto para esto) y tomar el código de cupón de la URL. - Hacer cálculos, cambiar elementos a nivel web completa, etc. en base a este código.
- Pasar estos parámetros (el código de cupón) a la ruta visitada.
Para simplificar, vamos a usar el +layout
top-level (/src/routes/+layout.js
y /src/routes/+layout.svelte
) porque queremos que afecte a todas las rutas de nuestra app.
Función load
en el archivo +layout.js
Añadimos una función load
que se ejecutará tanto server-side como client-side al visitar cualquier ruta, en /src/routes/+layout.js
.
En este ejemplo el parámetro de URL es coupon_code
(?coupon_code=DESC50
):
export async function load({ url }) {
// tomar el cupón de los parámetros de url
const couponCode = url.searchParams.get('coupon_code');
if (couponCode) {
// si existe `couponCode`,
// lo pasamos como una prop que usaremos en el componente svelte
return {
coupon: couponCode,
};
}
return {}
}
Aquí hemos puesto simplemente el código sin modificarlo o añadir nada, pero podríamos por ejemplo contrastarlo con un listado de cupones aceptados, calcular precios, etc. Y después agregar todo eso en las props y tenerlo disponible en toda la app.
Ahora podremos usar esta información en cualquier ruta de nuestra app. Estará disponible en la store page
que proporciona SvelteKit, dentro de page.data
.
Usar las props de +layout.js
en un Layout condicional
Vamos a usar esta data dentro del mismo +layout.svelte
para mostrar componentes en toda la web.
Así, como +layout.svelte
controla componentes que aparecerán en todas las páginas, podemos mostrar una barra promocional en toda la web solo si el cupón está en la URL.
En este caso podemos importar la data desde la store page
que te mencionaba, o directamente desde las props que recibe +layout.svelte
desde +layout.js
. Como esto es un ejemplo, vamos a ver ambas formas:
1. Desde la store page
En el archivo /src/routes/+layout.svelte
:
<script>
// importamos la store `page` ya que contiene `data`
import { page } from '$app/stores';
import { PromoBar } from '$lib/components/PromoBar';
</script>
{#if $page.data.coupon}
<PromoBar />
{/if}
<!-- recuerda que +layout siempre tiene que llevar `<slot />` -->
<slot />
<!-- ... -->
2. Desde las props que recibe +layout.svelte
<script>
import { PromoBar } from '$lib/components/PromoBar';
// aquí +layout.svelte recibe las props desde su función load en +layout.js
export let data;
// asignamos el valor de la prop data.coupon a una variable reactiva
$: coupon = data.coupon;
</script>
{#if coupon}
<PromoBar />
{/if}
<!-- recuerda que +layout siempre tiene que llevar `<slot />` -->
<slot />
<!-- ... -->
Recuerda que esta segunda opción es posible porque hemos devuelto las props desde la función load
del +layout.js
al mismo nivel.
Para tener esta información disponible en cualquier otra ruta, tendrás que tomarla desde la store page
como en el primer supuesto.
Puedes usar esta data en cualquier ruta
Igual que hemos usado $page.data.coupon
para un condicional en el +layout.svelte
general, esta data estará disponible en cualquier ruta, así que dentro de cualquier archivo svelte
puedes usarlo de esta manera.
También server-side
Si necesitas usarlo server-side para generar tu página (también en SSG), la función load
de cualquier ruta también tiene disponible esta información.
Por ejemplo, en una página que esté bajo el layout que hemos creado antes (ejemplo: /src/routes/productos/+page.js
):
La obtendrás usando la función parent
:
export async function load({ parent }) {
// `coupon` está disponible aquí porque lo hemos metido desde `+layout.js` inicialmente
const { coupon } = await parent();
// aquí usaríamos este código de cupón
// por ejemplo para solicitar o importar la data de esta ruta, etc.
// ...
}
Conclusión
Como la función load
en el archivo +layout.js
se ejecutará para cualquier ruta cubierta por este, podemos incluir lo que queramos dentro de las props que devuelve.
Esa información estará disponible en las funciones load
de todas las páginas con parent()
, y también client-side dentro de la store $page.data
.
No hay sección de comentarios, pero me encantaría escuchar tu opinión: escríbeme en Twitter y cuéntame!