Declarative fetching - move data fetching from your components to the router!
- no fetching code inside of your components - focus on presentation and UX rather than some infrastructure code
- no
beforeRouteEnter
,beforeRouteUpdate
guards to fetch data - no need to maintain
ref
orreactive
states - no need for a store (Vuex, Pinia etc.)
- URL string is all you need in simplest scenario
- Declarative fetching in the router
- Route parameters support
- Reactive fetching state
- Tiny - around 1kB thanks to native
fetch
- Easily configurable
- Custom fetch function support
Take a look at the live demo!
npm i vue-router-fetch
💡
vue-router
is a peer dependency so make sure its installed as well.
// main.js
import routerFetch from 'vue-router-fetch'
...
app.use(routerFetch, { router });
// router.js
{
path: '/',
meta: {
fetch: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/foos'
}
}
Results will be available under data
variable:
<template>
<h2>Foos</h2>
<ul>
<li v-for="item in data">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data } = useRouteFetch()
</script>
Use named fetch when you need to fetch multiple things:
// router.js
{
path: '/',
meta: {
fetch: {
foos: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/foos',
bars: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/bars'
}
}
}
Results will be available under corresponding variables :
<template>
<h2>Foos</h2>
<ul>
<li v-for="item in data.foos">{{item.name}}</li>
</ul>
<h2>Bars</h2>
<ul>
<li v-for="item in data.bars">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data } = useRouteFetch()
</script>
Provide your custom fetch function when you need to do a bit more than just hit the URL:
// router.js
{
path: '/',
meta: {
fetch: () => {
...
return myApi.fetchFoos(...)
}
}
}
💡 Custom fetch functions are available in single and named mode.
vue-router-fetch
can use route parameters with your fetch url as long as they have a matching name:
// router.js
{
path: '/home/:id',
meta: {
fetch: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/foos/:id'
}
}
You can use route params with a query string as well:
// router.js
{
path: '/home/:id',
meta: {
fetch: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/foos?id=:id'
}
}
Every fetch that you configured will have fetching state that you can use inside your template (ie. show/hide a loader).
Single fetch:
<template>
<h2>Foos</h2>
<ul v-if="!fetching">
<li v-for="item in data">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data, fetching } = useRouteFetch()
</script>
Named fetch:
<template>
<h2>Foos</h2>
<ul v-if="!fetching.foos">
<li v-for="item in data.foos">{{item.name}}</li>
</ul>
<h2>Bars</h2>
<ul v-if="!fetching.bars">
<li v-for="item in data.bars">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data, fetching } = useRouteFetch()
</script>
In case you need to access ie. status
code etc. useRouteFetch
will also expose reactive response for single an every named fetch.
Single fetch:
<template>
<h2>Foos</h2>
<h3>Status: {{response.status}}</h3>
<ul>
<li v-for="item in data">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data, response } = useRouteFetch()
</script>
Named fetch:
<template>
<h2>Foos</h2>
<h3>Status: {{response.foos.status}}</h3>
<ul>
<li v-for="item in data.foos">{{item.name}}</li>
</ul>
<h2>Bars</h2>
<h3>Status: {{response.bars.status}}</h3>
<ul>
<li v-for="item in data.bars">{{item.name}}</li>
</ul>
</template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data, response } = useRouteFetch()
</script>
useRouteFetch
returns fetch
function/object so you fetch from your component. This is specially usefull when you need to ie. refetch after some write operation:
// router.js
{
path: '/',
meta: {
fetch: {
foos: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/foos',
bars: 'https://632f9c11f5fda801f8d41dd6.mockapi.io/bars'
}
}
}
<template> ... </template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { data, fetch } = useRouteFetch()
function refreshEverything() {
fetch()
}
function refreshFoos() {
fetch.foos()
}
</script>
Applications are more than just fetching data so useRouteFetch
exposes get
, post
, patch
, put
and del
(delete) methods that you can call directly.
<template> ... </template>
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { get, post, del, patch } = useRouteFetch()
del('https://632f9c11f5fda801f8d41dd6.mockapi.io/foos/6')
.then(({ data, response }) => { ... })
</script>
Every method returns a promise that will resolve an Object
with data
(json data from a reponse) and response
if you need access to full reponse.
post
, push
and put
accept a payload to send as a second argument:
<script setup>
import { useRouteFetch } from 'vue-router-fetch'
const { post, patch } = useRouteFetch()
post('https://632f9c11f5fda801f8d41dd6.mockapi.io/foos', { name: 'new foo' })
.then(({ data, response }) => { ... })
patch('https://632f9c11f5fda801f8d41dd6.mockapi.io/foos/6', { name: 'update' })
.then(({ data, response }) => { ... })
</script>
You can pas your configuration to fetch
method on a global and per route basis
app.use(RouterFetch({ fetchOptions: { method: 'POST' } }))
That includes your static headers:
app.use(RouterFetch({ fetchOptions: { headers: { 'x-something': 'foo' } } }))
and dynamic headers, ie. authentication token:
app.use(RouterFetch({ fetchOptions: { headers: () => { 'authentication': ... } } }))
Same configuration can be passed to each route:
// router.js
{
path: 'foo',
meta: {
fetch: 'some.url',
fetchOptions: {
method: 'POST',
headers: { 'x-something': 'foo' }
}
}
}
💡 Route options will override global one!