“This is the 18th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

introduce#

Pinia started as an experiment in redesigning the look of the Vue Store using the Composition API around November 2019. From then on, the original principles are still the same, but Pinia works with Vue 2 and Vue 3 and doesn’t require you to use the composite API. The API for both is the same except for installation and SSR, and the documentation is specific to Vue 3 and provides comments about Vue 2 where necessary so that Vue 2 and Vue 3 users can read it!

Why use Pinia?#

Pinia is a repository for Vue that allows you to share state across components/pages. C This is true for single-page applications, but if it is rendered server-side, it exposes your application to security vulnerabilities. But even in small, single-page applications, you can get a lot of benefits from using Pinia:

  • Development tool support

    • Track the timeline of actions and mutations
    • Stores appear in components that use them
    • Time travel and easier debugging
  • Replacing a hot module

    • Modify your store without reloading the page
    • Maintain any existing state at development time
  • Plug-ins: Use plug-ins to extend Pinia functionality

  • Provide appropriate TypeScript support or auto-complete functionality for JS users

  • Server-side rendering support

Basic example#

This is what pinia looks like in terms of the API (be sure to check getting Started for full instructions). You first create a store:

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => {
    return { count: 0 }
  },
  // could also be defined as
  // state: () => ({ count: 0 })
  actions: {
    increment() {
      this.count++
    },
  },
})
Copy the code

Then use it in the component:

import { useCounterStore } from '@/stores/counter' export default { setup() { const counter = useCounterStore() Counter. Counter ++ // with autocompletion ✨ counter.$patch({count: counter.count + 1 }) // or using an action instead counter.increment() }, }Copy the code

You can even use a function (similar to a component setup()) to define a Store for more advanced use cases:

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }

  return { count, increment }
})
Copy the code

If you’re still unfamiliar with the Setup ()Composition API, don’t worry; Pinia also supports a similar set of map assistants, such as Vuex. You define storage in the same way, but then use mapStores(), mapState(), or mapActions() :

const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), getters: { double: (state) => state.count * 2, }, actions: { increment() { this.count++ } } }) const useUserStore = defineStore('user', { // ... }) export default { computed: { // other computed properties // ... // gives access to this.counterStore and this.userStore ... mapStores(useCounterStore, useUserStore) // gives read access to this.count and this.double ... mapState(useCounterStore, ['count', 'double']), }, methods: { // gives access to this.increment() ... mapActions(useCounterStore, ['increment']), }, }Copy the code

You’ll find more information about each map helper in the core concepts.

Why choosePinia#

Pinia (pronounced/PI ːnjʌ/, as in English “peenya”) is the closest word to pina (Spanish for pineapple), which is a valid package name. A pineapple is actually a group of individual flowers that come together to form multiple fruits. Like stores, each was born independently, but ultimately connected. It is also a delicious tropical fruit, native to South America.

A more realistic example#

This is a more complete EXAMPLE of an API that you will use in Pinia, even in JavaScript. For some, this may be enough to get started without further reading, but we still recommend that you look at the rest of the document, or even skip the example and return after reading all the core concepts.

import { defineStore } from 'pinia' export const todos = defineStore('todos', { state: () => ({ /** @type {{ text: string, id: number, isFinished: boolean }[]} */ todos: [], /** @type {'all' | 'finished' | 'unfinished'} */ filter: 'all', // type will be automatically inferred to number nextId: 0, }), getters: { finishedTodos(state) { // autocompletion! ✨ return state.todos.filter((todo) => todo.isfinished)}, unfinishedTodos(state) {return state.todos.filter((todo) =>! todo.isFinished) }, /** * @returns {{ text: string, id: number, isFinished: Boolean}[]} */ filteredTodos(state) {if (this.filter === 'finished') {// Call other getters with autocompletion ✨ return this.finishedTodos } else if (this.filter === 'unfinished') { return this.unfinishedTodos } return this.todos }, }, actions: { // any amount of arguments, return a promise or not addTodo(text) { // you can directly mutate the state this.todos.push({ text, id: this.nextId++, isFinished: false }) }, }, })Copy the code

Comparison with Vuex#

Pinia tries to be as close to Vuex’s ideas as possible. It was designed to test the proposal for the next iteration of Vuex and was successful as we currently have an open RFC for Vuex 5 with an API very similar to the one used by Pinia. Please note that I (Eduardo), author of Pinia, am a member of the vue.js core team and have been actively involved in the design of apis such as Router and Vuex. My personal intention for this project is to redesign the experience of using the global store while maintaining the approachable concept of Vue. I keep Pinia’s API as close to Vuex as it keeps moving forward to make it easier for people to migrate to Vuex and even merge the two projects (under Vuex) in the future.

RFC#

While Vuex collects as much feedback as possible from the community via RFC, Pinia does not. I tested ideas based on my experience developing applications, reading other people’s code, working for clients using Pinia, and answering questions on Discord. This allows me to provide an efficient solution for a variety of situations and application sizes. I often release and keep the library growing while keeping its core API intact.

Comparison with Vuex 3.x/4.x#

Vuex 3.x is Vue 2 of Vuex and Vuex 4.x is Vue 3

The Pinia API is very different from Vuex ≤4, namely:

  • mutationNo longer exists. They are often thought to beverylong. They initially brought DevTools integration, but that’s no longer an issue.
  • There is no need to create complex custom wrappers to support TypeScript, everything is typed, and the API is designed to take advantage of TS type inference wherever possible.
  • No more injecting magic strings, importing functions, calling them, and enjoying auto-complete!
  • There is no need to add stores dynamically, they are all dynamic by default and you won’t even notice. Note that you can still manually register with the store at any time, but because it’s automatic, you don’t have to worry.
  • There is no longerThe moduleThe nested structure of. You can still import and from another storeuseStores are implicitly nested stores, but Pinia provides a flat structure through design while still supporting a cross composition of stores.You can even have cyclic store dependencies.
  • There is noModule of the namespace. Given the flat architecture of stores, “namespace” stores are inherent in the way they are defined, and you could say that all stores are namespace.

For more detailed instructions on how to convert an existing Vuex ≤4 project to use Pinia, see the Migration from Vuex guide.