Introduction to Pinia
Pinia is a state management library designed specifically for the design, which provides a simple and intuitive way to manage the state of an application. When using Pinia, it is easy to create storage that defines states and then bind them to Vue components to enable them to use that state. Compared with the Vuex mentioned in the previous blog, Pinia is simpler and easier to use, smaller in size, and has better TypeScript support and plug-in system.
In the official website, we can see that Pinia has now replaced Vuex and become part of the Vue ecosystem.
Install and configure Pinia
Installing and configuring Pinia is very simple. Like other Vue plugins, Pinia needs to be installed through yarn or npm and bound to the Vue application. You can install it using the following command:
yarn add pinia # Or use npmnpm install pinia
After installing the Pinia package, you need to import the createPinia function in the file and bind the Pinia plugin to the Vue application, as shown below:
import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './'; const app = createApp(App); const pinia = createPinia(); (pinia); ('#app');
Use the createPinia() function to create and initialize the Pinia plugin instance, bound it to the Vue application to use (pinia). At this point, we can use Pinia to manage the status of the Vue application.
The core of Pinia
Store
Store is the core concept of managing state in Pinia. It is equivalent to the state in a Vue component, but the Store is a standalone module.
Store is defined with defineStore() . Its first parameter requires a unique name. This name, also used as id , must be passed in. Pinia will use it to connect store and devtools. In order to develop habitual usage, naming the returned function as use… is a convention that conforms to the style of a combination function.
The second parameter of defineStore() can accept two types of values: the Setup function or the Option object.
Sample code for defining the Store:
import { defineStore } from 'pinia' // You can name the return value of `defineStore()` arbitrarily, but it is best to use the name of the store, starting with `use` and ending with `Store`. (For example, `useUserStore`, `useCartStore`, `useProductStore`)// The first parameter is the unique ID of the Store in your application.export const useAlertsStore = defineStore('alerts', { // Other configurations...})
State
State is where data is stored in the store. By defining a State, data can be accessed and modified anywhere in the store.
In Pinia, state is defined as a function that returns the initial state. This allows Pinia to support both server and client.
The example code for defining a State is as follows:
import { defineStore } from 'pinia' const useStore = defineStore('storeId', { // For complete type reasoning, it is recommended to use arrow functions state: () => { return { // All of these properties will automatically infer their types count: 0, name: 'Eduardo', isAdmin: true, items: [], hasChanged: true, } }, })
Getter
Getter is used to get data derived from state, similar to the computed computed properties in Vue components. They can be defined by the getters property in defineStore(). It is recommended to use the arrow function, and it will receive state as the first parameter:
export const useStore = defineStore('main', { state: () => ({ count: 0, }), getters: { doubleCount: (state) => * 2, }, })
Action
Action is equivalent to a method in a component. They can be defined by the actions property in defineStore(); Action is a way to encapsulate asynchronous operations in the store. It is a function that can be called, or it can receive parameters and modify the state in the store. Actions should always be synchronous and return a Promise object so that the results are handled well when handling asynchronous operations.
Actions in Pinia are created by defineStore and can be used by defining them in actions. For example, the following is the Action definition in a store:
import { defineStore } from 'pinia' export const myStore = defineStore('myStore',{ state: () => ({ message: 'Hello', }), actions: { async fetchMessage() { const response = await fetch('http://127.0.0.1:5173/message') const data = await () = }, }, })
In the example above, we define an Action for myStore, fetchMessage(), which fetches data from the background API and updates the status in the store. We can then call the Action from a component or other Action:
import { useStore } from 'pinia' export default { setup() { const store = useStore('myStore') function handleClick() { () } return { handleClick, } }, }
In the above code, we use the useStore hook in the component to get the store instance and then pass it to the fetchMessage() method. This method will get data from the background of the application and update the status in memory. Finally, a handleClick() method is exposed so that the component can call it and trigger Action .
Create and use Pinia
Create Pinia
We have installed and configured Pinia before. Before creating Pinia, for the unified management and maintainability of the code, we still create a store folder first, and then create the relevant Pinia. The specific steps are as follows
- Create a new store folder under the src folder, and all the codes that require Pinia to manage state are placed in this folder.
- Create a new file in the store folder. After the creation is completed, open the file
- Introduce the defineStore method in Pinia into a file
import { defineStore } from 'pinia'
- Create a defineStore object, define a useMovieListStore to receive the object created by defineStore, and export it through export default
const useMovieListStore = defineStore('movie',{ state: () => ({ isShow: true, movies: [], }), getters: { getIsShow() { return }, getMovies() { return }, }, actions: { setIsShow(value) { = value }, async fetchMovies() { const response = await fetch('/movies') const data = await () = data }, }, }) export default useMovieListStore
In the above code, we use action to define two methods, onesynchronousmethod setIsShow,
oneasynchronousMethod fetchMovies
Notice:It should be noted here that the official suggests that when defining hook functions, we recommend using the naming method at the beginning of the store at the end of the store to name the objects created above, such as the useMovieListStore above
Using Pinia
We have created Pinia before, and next we can use it in the component.
To use store in Vue components, we need to access the instance of the store through the useStore() function.
The steps to use Pinia in Vue components are as follows
- First use import to import the useStore in Pinia
import { useStore } from 'pinia'
- Create useStore object
const store = useStore('movie')
- Where the state needs to be retrieved, the state is obtained through the () defined above.
return { isShow: (), }
The complete example code in this is as follows:
<template> <nav> <ul> <li v-show="isShow">{{ $ }} </li> <li><router-link to="/">Home</router-link></li> <li><router-link to="/movies">Movies</router-link></li> </ul> </nav> </template> <script> import { defineComponent } from 'vue' import { useStore } from 'pinia' export default defineComponent({ name: 'Menu', setup() { const store = useStore('movie') return { isShow: (), } }, }) </script>
Pinia's Option Store method definition Store
Option Store method defines the option API of Store and Vue. We define it by passing in an Option object with state, actions and getters attributes. The sample code is as follows:
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), getters: { double: (state) => * 2, }, actions: { increment() { ++ }, }, })
We can think that state is the data of the store, getters is the computed property of the store, and actions are methods.
Pinia's Setup Store method definition Store
The Setup Store is slightly different from the Option Store. It is similar to the setup function of the Vue combination API. We pass in a function that defines some responsive properties and methods and returns an object with the properties and methods we want to expose. The sample code is as follows:
export const useCounterStore = defineStore('counter', () => { const count = ref(0) function increment() { ++ } return { count, increment } })
In the Setup Store:
- ref() is the state property
- computered() is getters
- function() is actions
Sample code
The following is an example to fully illustrate the usage of Pinia state management. Now we need to achieve the following effects:
Now two functions need to be completed on the page. One function is to control the display and hiding of the button at the bottom menu bar when jumping from different pages; the other function is to connect to the network through a function to obtain the movie list and display it on the details page
In the option API, the implementation code is as follows:
- Code in
// import { createApp } from 'vue' import App from './' import { createPinia } from 'pinia' import { movieStore } from './store/movieStore' const app = createApp(App) (createPinia()) (movieStore) ('#app')
- Code in the store folder
// store/ import { defineStore } from 'pinia' export const useMovieListStore = defineStore('movie',{ state: () => ({ isShow: true, movies: [], }), getters: { getIsShow() { return }, getMovies() { return }, }, actions: { setIsShow(value) { = value }, async fetchMovies() { const response = await fetch('/movies') const data = await () = data }, }, })
- Code of files in components folder
<!-- components/ --> <template> <nav> <ul> <li v-show="isShow">{{ $ }} </li> <li><router-link to="/">Home</router-link></li> <li><router-link to="/movies">Movies</router-link></li> </ul> </nav> </template> <script> import { defineComponent } from 'vue' import { useStore } from 'pinia' export default defineComponent({ name: 'Menu', setup() { const store = useStore('movie') return { isShow: (), } }, }) </script>
- Code under components folder
<!-- components/ --> <template> <ul> <li v-for="movie in movies" :key=""> <router-link :to="`/movies/${}`">{{ }}</router-link> </li> </ul> </template> <script> import { defineComponent } from 'vue' import { useStore } from 'pinia' export default defineComponent({ name: 'MovieList', setup() { const store = useStore('movie') () return { movies: (), } }, }) </script>
- The code under the views folder
<!-- views/ --> <template> <div v-if="movie"> <h2>{{ }}</h2> <p>{{ }} </p> </div> <div v-else> <h2>Movie Not Found</h2> </div> </template> <script> import { defineComponent } from 'vue' import { useRoute } from 'vue-router' import { useStore } from 'pinia' export default defineComponent({ name: 'MovieDetails', setup() { const route = useRoute() const store = useStore('movie') const movieId = const movie = ().find((movie) => === movieId) return { movie, } }, }) </script>
The above code shows how to share and manage state using the store, getter, and action in Pinia. Among them, movieStore defines a store that contains two states: isShow and movies, and an action to modify isShow and get the movie list. In the component, we use the useStore hook to get the isShow status from the store and control the display and hiding of the button in the bottom menu bar according to its value. In the component, we use the useStore hook to get the movie status from the store and use the fetchMovies() action to get the movie list from the network. In the component, we use the useRoute hook to get the routing parameter id of the current page, useStore hook to get the movies status from the store, and get the detailed information of the current movie based on the movieId and getMovies() getter.
Note that in the setup() hook, we use the useStore hook to get state and perform operations from the store. Since the useStore hook returns a responsive proxy, we do not need to manually update the state responsively. Moreover, we can decouple components from the store to make them easier to test and reuse.
In the combined API, the implementation code is slightly different. Here we only use the page examples. Other pages are written in a similar way and are not displayed. The page code is as follows:
<!-- components/ --> <template> <ul> <li v-for="movie in movies" :key=""> <router-link :to="`/movies/${}`">{{ }}</router-link> </li> </ul> </template> <script setup> import { onMounted, computed } from 'vue' import { useStore } from 'pinia' const store = useStore('movie') onMounted(() => { () }) const movies = computed(() => ()) </script>
OK, this is the introduction to the use of Pinia for global state management in Vue3
Summarize
This is the end of this article about how to use Pinia in Vue3. For more related content on using Pinia in Vue3, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!