|
1 | 1 | # Data Loaders
|
2 | 2 |
|
| 3 | +Data loaders streamline any asynchronous state management with Vue Router, like **Data Fetching**. Adopting Data loaders ensures a consistent and efficient way to manage data fetching in your application. Keep all the benefits of using libraries like [Pinia Colada](./colada/) or [Apollo](./apollo/) and integrate them seamlessly with client-side navigation. |
| 4 | + |
| 5 | +This is achieved by extracting the loading logic **outside** of the component `setup` (unlike `<Suspense>`). This way, the loading logic can be executed independently of the component lifecycle, and the component can focus on rendering the data. Data Loaders are automatically collected and awaited within a navigation guard, ensuring the data is ready before rendering the component. |
| 6 | + |
| 7 | +## Features |
| 8 | + |
| 9 | +- Parallel data fetching and deduplication |
| 10 | +- Automatic loading state management |
| 11 | +- Error handling |
| 12 | +- Extensible by loader implementations |
| 13 | +- SSR support |
| 14 | +- Prefetching data support |
| 15 | + |
3 | 16 | ## Installation
|
4 | 17 |
|
| 18 | +After installing [unplugin-vue-router](../introduction.md), install the `DataLoaderPlugin` **before the `router`**. |
| 19 | + |
| 20 | +```ts{12-15} twoslash |
| 21 | +import 'unplugin-vue-router/client' |
| 22 | +import './typed-router.d' |
| 23 | +// @moduleResolution: bundler |
| 24 | +// ---cut--- |
| 25 | +import { createApp } from 'vue' |
| 26 | +import { routes } from 'vue-router/auto-routes' |
| 27 | +import { createRouter, createWebHistory } from 'vue-router' |
| 28 | +import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' // [!code ++] |
| 29 | +
|
| 30 | +const router = createRouter({ |
| 31 | + history: createWebHistory(), |
| 32 | + routes, |
| 33 | +}) |
| 34 | +
|
| 35 | +const app = createApp({}) |
| 36 | +// Register the plugin before the router |
| 37 | +app.use(DataLoaderPlugin, { router }) // [!code ++] |
| 38 | +// adding the router will trigger the initial navigation |
| 39 | +app.use(router) |
| 40 | +app.mount('#app') |
| 41 | +``` |
| 42 | + |
5 | 43 | ## Quick start
|
| 44 | + |
| 45 | +There are different data loaders implementation, the most simple one is the [Basic Loader](./basic/) which always reruns data fetching. A more efficient one, is the [Colada Loader](./colada/) which uses [@pinia/colada](https://github.com/posva/pinia-colada) under the hood. In the following examples, we will be using the _basic loader_. |
| 46 | + |
| 47 | +Loaders are [composables](https://vuejs.org/guide/reusability/composables.html) defined through a `defineLoader` function like `defineBasicLoader` or `defineColadaLoader`. They are _used_ in the component `setup` to extract the needed information. |
| 48 | + |
| 49 | +To get started, _define_ and _export_ a loader from a page: |
| 50 | + |
| 51 | +```vue{2,5-7,11-16} twoslash |
| 52 | +<script lang="ts"> |
| 53 | +import 'unplugin-vue-router/client' |
| 54 | +import './typed-router.d' |
| 55 | +// ---cut--- |
| 56 | +import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic' |
| 57 | +import { getUserById } from '../api' |
| 58 | +
|
| 59 | +export const useUserData = defineBasicLoader('/users/[id]', async (route) => { |
| 60 | + return getUserById(route.params.id) |
| 61 | +}) |
| 62 | +</script> |
| 63 | +
|
| 64 | +<script setup lang="ts"> |
| 65 | +const { |
| 66 | + data: user, // the data returned by the loader |
| 67 | + isLoading, // a boolean indicating if the loader is fetching data |
| 68 | + error, // an error object if the loader failed |
| 69 | + reload, // a function to refetch the data without navigating |
| 70 | +} = useUserData() |
| 71 | +</script> |
| 72 | +
|
| 73 | +<template> |
| 74 | + <main> |
| 75 | + <p v-if="isLoading">Loading...</p> |
| 76 | + <template v-else-if="error"> |
| 77 | + <p>{{ error.message }}</p> |
| 78 | + <button @click="reload()">Retry</button> |
| 79 | + </template> |
| 80 | + <template v-else> |
| 81 | + <p>{{ user }}</p> |
| 82 | + </template> |
| 83 | + </main> |
| 84 | +</template> |
| 85 | +``` |
| 86 | + |
| 87 | +The loader will automatically run when the route changes, for example when navigating to `/users/1`, even when coming from `/users/2`, the loader will fetch the data and delay the navigation until the data is ready. |
| 88 | + |
| 89 | +On top of that, you are free to _reuse_ the returned composable `useUserData` in any other component, and it will automatically share the same data fetching instance. |
| 90 | + |
| 91 | +## Why Data Loaders? |
| 92 | + |
| 93 | +Data fetching is the most common need for a web application. There are many ways of handling data fetching, and they all have their pros and cons. Data loaders are a way to streamline data fetching in your application. Instead of forcing you to choose between different libraries, data loaders provide a consistent way to manage data fetching in your application no matter the underlying library or strategy you use. |
0 commit comments