Skip to content

Quick Start

Get a quick overview of how to use Pinia Colada in your project.

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

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
,
status
,
error
,
} =
useQuery
({
key
: ['products-list'],
query
:
getAllProducts
,
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
status
=== '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
,
status
,
error
,
} =
useQuery
({
key
: () => ['products',
route
.
params
.
id
as string],
query
: () =>
getProductById
(
route
.
params
.
id
as string),
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
status
=== '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. Unlinke queries, mutations only require a mutation function. Providing a key is optional and, by default, it allows the mutation to automatically invalidate queries with a matching key once it settles:

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 async status to disable a form
mutateAsync
,
status
,
error
,
} =
useMutation
({
key
: (
contact
) => ['contacts',
contact
.
id
],
mutation
: (
contact
: Contact) =>
updateContact
(
contact
),
}) </script> <template> <
main
>
<
LoadingIndicator
v-if="
status
=== '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 ✨.

Optimistic updates

Optimistic updates are all about displaying the upcoming state before the mutation settles. This is useful to provide instant feedback to the user. There are mainly two ways to achieve this: via the UI or via the cache:

Via the UI

vue
<!--  -->

Via the cache

vue
<!--  -->

Released under the MIT License.