Skip to main content

Pinia for State Management

ยท 3 min read
Zoe Laventhol
Full Stack Collaborator @ EuFMD

Using Pinia for state management in Vue appsโ€‹

๐Ÿ What is Pinia?โ€‹

Pinia allows you to store data and methods (aka variables and functions) in a central way, and import them to different components throughout your app. This can simplify your code by importing and using variables and functions only in the components where they are needed. This avoids prop drilling and several layers of callback functions!

Here is the documentation. ๐Ÿ“–

When to use it?โ€‹

โœ…ย Use Pinia to store any data and methods that need to be accessible across multiple components. Ex:

  • myData needs to be set in Component.vue, but displayed in SiblingComponent.vue
  • Component.vue needs to fetch data based on some action in that component, but SiblingComponent.vue needs to display, edit or remove the same data.
  • myData and otherData are rendered in different components, but are both used in a third component to calculate some outcome.

โŒย Do not use Pinia for data that is only used temporarily, or in a single component. Ex:

  • Component.vue temporarily sets a selectedItem - some function is performed on the selected item, then it clears when a new item is selected.
  • Component.vue uses specificData that never needs to be passed to or used in other components.

How to use it?โ€‹

Create a store ๐Ÿ—๏ธโ€‹

First, create your store file and name it with this pattern: useExampleStore.js

  • i.e. use + YourStoreName + Store
  • so for example, for RMT's disease status data: useDiseaseStatusStore.js

Step-by-step instructions in comments below. You can look at examples in the codebase in client > src > stores.

// ******* STEP 1: import defineStore at the top *******
import { defineStore } from "pinia";

// ******* STEP 2: export your store, and after defineStore, give your store a unique descriptive name *******
export const useExampleStore = defineStore("example", {
// ******* STEP 3: define your data/variables in state *******
state: () => ({
myVariable: [],
anotherVariable: "I โค๏ธ Pinia",
}),

// ******* STEP 4: define your functions/methods in "actions" *******
actions: {
async myFunction(params) {
// your code...
},
anotherFunction() {
// your code...
},
},
});

// ******* THAT'S IT! Congrats :) *******

Use a store ๐Ÿงคโ€‹

Hereโ€™s a ๐ŸŽฌย how-to video

Process to use stored data or methods in any component is:

  1. In <script>, import:
    1. the correct store
    2. mapState if youโ€™re using data/variables
    3. mapActions if youโ€™re using functions/methods
import { useExampleStore } from "@/stores/useExampleStore";
import { mapState, mapActions } from "pinia";
  1. For data/variables, add a computed property in your <script>, and use mapState to destructure your stored data:
computed: {
...mapState(useExampleStore, ['myVariable', 'anotherVariable'])
},
  1. For functions/methods, use mapActions in your methods to destructure the stored functions. You do not need to include params, just function names:
methods: {
...mapActions(useExampleStore, ['myFunction', 'anotherFunction'])
},
  1. Then you can use as usual! i.e. Use the variables in your <template>, call the functions, etc., with the same syntax as if they were standard data or methods.
<div>
<select @change="myFunction(value)">
<option v-for="item in myVariable" :key="item.id" :value="item.name">
{{ item.name }}
</option>
</select>
</div>