Skip to content

Quick Start

Pinia Colada is the perfect companion to Pinia to handle async state management in your Vue applications. It wil remove the need to write boilerplate code for data fetching and transparently bring caching, deduplication, invalidation, and much more. Allowing you to focus on building the best user experience for your users.

Get a quick overview of how to use Pinia Colada in your project or if you prefer to directly play with the code you can play with Pinia Colada in this Stackblitz project.

Installation

Install Pinia Colada alongside Pinia using your favorite package manager:

bash
npm i @pinia/colada

Setup

Install the PiniaColada plugin after Pinia (so it picks it up automatically ✨):

ts
import { 
createApp
} from 'vue'
import {
createPinia
} from 'pinia'
import {
PiniaColada
} from '@pinia/colada'
const
app
=
createApp
({})
app
.
use
(
createPinia
())
app
.
use
(
PiniaColada
)
app
.
mount
('#app')

Usage

Let's see a quick example that covers the basics of queries, mutations and query invalidation.

Querying

Query data with useQuery() in any component. Always provide a key and an async query:

vue
<script setup lang="ts">
import { 
useQuery
} from '@pinia/colada'
import {
getAllProducts
} from '@/api/products'
import
ProductItem
from '@/components/ProductItem.vue'
const { // when using multiple queries in the same component, // it is convenient to rename `data`
data
:
productList
,
asyncStatus
,
error
,
} =
useQuery
({
key
: ['products-list'],
query
:
getAllProducts
,
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
asyncStatus
=== 'loading'" />
<
div
v-if="
error
">
<
ErrorMessage
:error
="
error
" />
</
div
>
<
div
v-else-if="
productList
">
<
div
v-for="
product
in
productList
"
:key
="
product
.
id
">
<!-- add prefetch here : @mouseover="prefetch(product.id)" --> <
ProductItem
:product
="
product
" />
</
div
>
</
div
>
</
main
>
</template>
vue
<script setup lang="ts">
import { 
useQuery
} from '@pinia/colada'
import {
useRoute
} from 'vue-router'
import {
getProductById
} from '@/api/products'
import
ProductItemDetail
from '@/components/ProductItemDetail.vue'
// in this example we use the url params in the query to fetch // a specific product const
route
=
useRoute
()
const {
data
:
product
,
asyncStatus
,
error
,
} =
useQuery
({
key
: () => ['products',
route
.
params
.
id
as string],
query
: () =>
getProductById
(
route
.
params
.
id
as string),
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
asyncStatus
=== 'loading'" />
<
div
v-if="
error
">
<
ErrorMessage
:error
="
error
" />
</
div
>
<
div
v-else
class
="flex flex-wrap">
<
ProductItemDetail
:product
="
product
" />
</
div
>
</
main
>
</template>

Mutating data

Mutate data with useMutation() in any component. Unlike queries, mutations only require a mutation function, the key is optional:

vue
<script setup lang="ts">
import { 
useMutation
} from '@pinia/colada'
import { type Contact,
updateContact
} from '@/api/contacts'
import
ContactDetail
from '@/components/ContactDetail.vue'
const
props
=
defineProps
<{
contact
: Contact }>()
const { // we use the async version of the mutation so ContactDetail // can use the asyncStatus to disable a form
mutateAsync
,
asyncStatus
,
error
,
} =
useMutation
({
mutation
: (
contact
: Contact) =>
updateContact
(
contact
),
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
asyncStatus
=== 'loading'" />
<
div
v-if="
error
">
<
ErrorMessage
:error
="
error
" />
</
div
>
<
div
v-else>
<
ContactDetail
:contact
="
props
.
contact
" @
update
="
mutateAsync
" />
</
div
>
</
main
>
</template>

Invalidated queries will be refetched automatically if they are actively being used ✨.

Going further

Pinia Colada has much more to offer! It can greatly improves your application's performance and user experience. Check out the following guides to learn more:

Released under the MIT License.