Pinia First Steps
If you're using Vue and need a state management solution for your app, Pinia is the way to go. It’s so easy to use that we can dive right in.
Installation
First, install pinia:
npm install pinia
Then, in your main.ts
file:
// ...
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
// ...
Creating a Store
To create a store, use defineStore
from Pinia.
import { defineStore } from 'pinia';
export const usePostsStore = defineStore('postsStore', {});
The first argument in defineStore
is the name of our store. The second argument, in this case, is an object (option store) that holds our state, getters, and actions. I’ll explain these in a moment.
The second argument can also be a function (setup store). I recommend using the option store, but if you want to explore other scenarios, here's the link.
State
The state holds the data that will be used in your components or other stores. It’s a good practice to define types for it.
We'll define our state as the first property of the object. It should be a function that returns our state.
import { defineStore } from 'pinia';
import type { Post } from './types';
type PostsStoreState = {
posts: Post[];
};
export const usePostsStore = defineStore('postsStore', {
state: (): PostsStoreState => ({
posts: [],
}),
});
Actions
Actions are methods that allow us to fetch data, set loading states, handle errors, or manipulate our state.
To access the state within actions, use the this
keyword. When working with Pinia, this
is crucial — it allows you to access state e.g this.posts
, call other actions, or use getters. Here's the basic Pinia action:
export const usePostsStore = defineStore('postsStore', {
state: (): PostsStoreState => ({
posts: [],
}),
actions: {
async getPosts() {
try {
this.posts = await api.getPosts();
} catch (error) {
console.error(error);
}
},
},
});
That’s it! Actions can take arguments, return values, and interact with other stores.
Getters
Sometimes we need specific data rather than the entire posts
array. For example, we might only want the posts that have been liked. Instead of filtering posts in a component, we can define a getter.
export const usePostsStore = defineStore('postsStore', {
state: (): PostsStoreState => ({
posts: [],
}),
getters: {
getLikedPosts: (state) => {
return state.posts.filter((post) => post.isLiked);
},
},
actions: {
async getPosts() {
try {
this.posts = await api.getPosts();
} catch (error) {
console.error(error);
}
},
},
});
Like actions, getters are functions inside an object, taking state
as the first argument. We can also use this
to access other getters or state properties. If you need to pass arguments, return a function that accepts them.
Using the Pinia Store
Now let’s see how to use our store in a component. Import and initialize it as follows:
<script setup lang="ts">
import { usePostsStore } from '@stores/postsStore';
const postsStore = usePostsStore();
</script>
You can now use postsStore
in your component. However, avoid destructuring properties directly from the store, as it breaks reactivity. Instead, use storeToRefs
from Pinia.
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { usePostsStore } from '@stores/postsStore';
const postsStore = usePostsStore();
const { posts } = storeToRefs(postsStore);
</script>
And that’s it! You now have all the knowledge needed to start using Pinia in your Vue applications.
Thanks for reading!