Convert Figma logo to code with AI

vuejs logopinia

🍍 Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support

13,059
1,046
13,059
40

Top Related Projects

60,792

A JS library for predictable global state management

27,458

Simple, scalable state management.

46,119

🐻 Bear necessities for state management in React

8,477

The Redux Framework

Business logic with ease ☄️

Quick Overview

Pinia is the official state management library for Vue.js applications. It provides a simple and intuitive API for managing global state, with full TypeScript support and devtools integration. Pinia is designed to be lightweight and flexible, making it suitable for projects of all sizes.

Pros

  • Excellent TypeScript support with autocompletion
  • Modular design allows for better code organization and scalability
  • Seamless integration with Vue 3 Composition API
  • Built-in devtools support for easy debugging and state inspection

Cons

  • Learning curve for developers new to state management concepts
  • Limited ecosystem compared to older solutions like Vuex
  • May be overkill for small projects with simple state requirements

Code Examples

  1. Creating a store:
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    },
  },
})
  1. Using the store in a component:
<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
</script>

<template>
  <div>Count: {{ counter.count }}</div>
  <button @click="counter.increment()">Increment</button>
</template>
  1. Composing stores:
import { defineStore } from 'pinia'
import { useUserStore } from './user'

export const useCartStore = defineStore('cart', {
  state: () => ({ items: [] }),
  getters: {
    total() {
      return this.items.reduce((sum, item) => sum + item.price, 0)
    },
  },
  actions: {
    async checkout() {
      const userStore = useUserStore()
      await api.checkout(this.items, userStore.token)
      this.items = []
    },
  },
})

Getting Started

  1. Install Pinia:
npm install pinia
  1. Create a Pinia instance in your main.js:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')
  1. Create a store:
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    },
  },
})
  1. Use the store in a component:
<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
</script>

<template>
  <div>Count: {{ counter.count }}</div>
  <button @click="counter.increment()">Increment</button>
</template>

Competitor Comparisons

60,792

A JS library for predictable global state management

Pros of Redux

  • Widely adopted and battle-tested in large-scale applications
  • Extensive ecosystem with many middleware options and developer tools
  • Framework-agnostic, can be used with any UI library or framework

Cons of Redux

  • Steeper learning curve due to concepts like reducers, actions, and middleware
  • More boilerplate code required for setting up stores and actions
  • Can be overkill for smaller applications or simpler state management needs

Code Comparison

Redux:

const store = createStore(reducer);
const action = { type: 'INCREMENT' };
store.dispatch(action);
const state = store.getState();

Pinia:

const store = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }
  }
});
store.increment();
const count = store.count;

Redux requires more setup code and explicit action dispatching, while Pinia offers a more concise and intuitive API. Pinia's store definition is more straightforward, with state and actions defined in a single object. Redux, on the other hand, separates concerns into reducers, actions, and store creation, which can lead to more verbose code but also provides more flexibility for complex state management scenarios.

27,458

Simple, scalable state management.

Pros of MobX

  • Framework-agnostic, can be used with React, Vue, or vanilla JavaScript
  • Automatic tracking of observables, reducing boilerplate code
  • Supports computed values and reactions out of the box

Cons of MobX

  • Steeper learning curve due to its more complex API
  • Less predictable state updates, as mutations can happen anywhere
  • Potential for overuse of observables, leading to performance issues

Code Comparison

MobX:

import { makeObservable, observable, action } from "mobx";

class Store {
  count = 0;
  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action
    });
  }
  increment() {
    this.count++;
  }
}

Pinia:

import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++;
    }
  }
});

Both MobX and Pinia offer state management solutions, but they differ in their approach and ecosystem integration. MobX provides a more flexible, framework-agnostic solution with powerful reactive programming concepts, while Pinia offers a simpler, Vue-specific state management experience with better TypeScript support and Vue devtools integration.

46,119

🐻 Bear necessities for state management in React

Pros of Zustand

  • Framework-agnostic, can be used with any UI library or vanilla JavaScript
  • Simpler API with less boilerplate code
  • Supports middleware and devtools out of the box

Cons of Zustand

  • Less opinionated structure, which may lead to inconsistent patterns in larger projects
  • Lacks built-in TypeScript support for action typing (though can be added manually)
  • No built-in support for modules or namespacing

Code Comparison

Zustand:

import create from 'zustand'

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

Pinia:

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    },
  },
})

Both Zustand and Pinia are popular state management libraries, but they cater to different needs. Zustand offers simplicity and flexibility, making it a great choice for small to medium-sized projects or when working outside the Vue ecosystem. Pinia, being tailored for Vue.js, provides a more structured approach with better TypeScript integration, making it ideal for large-scale Vue applications.

8,477

The Redux Framework

Pros of Rematch

  • Framework-agnostic, works with React, Vue, and other libraries
  • Built-in support for async actions and effects
  • More flexible model structure with less boilerplate

Cons of Rematch

  • Smaller community and ecosystem compared to Pinia
  • Less Vue-specific optimizations and integrations
  • Steeper learning curve for Vue developers familiar with Vuex/Pinia patterns

Code Comparison

Rematch:

const count = {
  state: 0,
  reducers: {
    increment(state, payload) {
      return state + payload
    }
  },
  effects: (dispatch) => ({
    async incrementAsync(payload) {
      await new Promise(resolve => setTimeout(resolve, 1000))
      dispatch.count.increment(payload)
    }
  })
}

Pinia:

export const useCountStore = defineStore('count', {
  state: () => ({ count: 0 }),
  actions: {
    increment(amount) {
      this.count += amount
    },
    async incrementAsync(amount) {
      await new Promise(resolve => setTimeout(resolve, 1000))
      this.increment(amount)
    }
  }
})

Both Rematch and Pinia offer state management solutions, but Rematch is more flexible and framework-agnostic, while Pinia is tailored for Vue.js applications. Rematch provides a more Redux-like approach with separate reducers and effects, whereas Pinia follows a simpler, more Vue-oriented structure with combined state and actions.

Business logic with ease ☄️

Pros of Effector

  • Framework-agnostic, can be used with any UI library or framework
  • Offers more fine-grained control over state updates and side effects
  • Provides powerful tools for handling asynchronous operations and complex data flows

Cons of Effector

  • Steeper learning curve due to its unique approach and concepts
  • Less integrated with Vue.js ecosystem compared to Pinia
  • Smaller community and fewer ready-made plugins/extensions

Code Comparison

Effector:

import {createStore, createEvent} from 'effector'

const increment = createEvent()
const $counter = createStore(0)
  .on(increment, state => state + 1)

Pinia:

import {defineStore} from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    }
  }
})

Both Effector and Pinia are state management solutions, but they differ in their approach and target audience. Effector is more flexible and powerful, suitable for complex applications across different frameworks. Pinia, on the other hand, is specifically designed for Vue.js applications, offering a simpler API and better integration with the Vue ecosystem. The choice between them depends on the project requirements, team expertise, and the specific framework being used.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Pinia logo


npm package build status


Pinia

Intuitive, type safe and flexible Store for Vue

  • 💡 Intuitive
  • 🔑 Type Safe
  • ⚙️ Devtools support
  • 🔌 Extensible
  • 🏗 Modular by design
  • 📦 Extremely light
  • ⛰️ Nuxt Module

Pinia works with both Vue 2 and Vue 3.

Pinia is the most similar English pronunciation of the word pineapple in Spanish: piña. A pineapple is in reality a group of individual flowers that join together to create a multiple fruit. Similar to stores, each one is born individually, but they are all connected at the end. It's also a delicious tropical fruit indigenous to South America.

👉 Demo with Vue 3 on StackBlitz

👉 Demo with Nuxt 3 on StackBlitz

Help me keep working on this project 💚

Silver Sponsors

Route Optimizer and Route Planner Software Prefect VueMastery

Bronze Sponsors

Storyblok Nuxt UI Pro Templates Antony Konstantinidis Stanislas Ormières


FAQ

A few notes about the project and possible questions:

Q: Is Pinia the successor of Vuex?

A: Yes

Q: What about dynamic modules?

A: Dynamic modules are not type safe, so instead we allow creating different stores that can be imported anywhere

Installation

# or pnpm or yarn
npm install pinia

If you are using Vue <2.7, make sure to install latest @vue/composition-api:

npm install pinia @vue/composition-api

Usage

Install the plugin

Create a pinia (the root store) and pass it to app:

// Vue 3
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')
// Vue 2
import { createPinia, PiniaVuePlugin } from 'pinia'

Vue.use(PiniaVuePlugin)
const pinia = createPinia()

new Vue({
  el: '#app',
  // other options...
  // ...
  // note the same `pinia` instance can be used across multiple Vue apps on
  // the same page
  pinia,
})

For more detailed instructions, including Nuxt configuration, check the Documentation.

Create a Store

You can create as many stores as you want, and they should each exist in different files:

import { defineStore } from 'pinia'

// main is the name of the store. It is unique across your application
// and will appear in devtools
export const useMainStore = defineStore('main', {
  // a function that returns a fresh state
  state: () => ({
    counter: 0,
    name: 'Eduardo',
  }),
  // optional getters
  getters: {
    // getters receive the state as first parameter
    doubleCounter: (state) => state.counter * 2,
    // use getters in other getters
    doubleCounterPlusOne(): number {
      return this.doubleCounter + 1
    },
  },
  // optional actions
  actions: {
    reset() {
      // `this` is the store instance
      this.counter = 0
    },
  },
})

defineStore returns a function that has to be called to get access to the store:

import { useMainStore } from '@/stores/main'
import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const main = useMainStore()

    // extract specific store properties
    const { counter, doubleCounter } = storeToRefs(main)

    return {
      // gives access to the whole store in the template
      main,
      // gives access only to specific state or getter
      counter,
      doubleCounter,
    }
  },
})

Documentation

To learn more about Pinia, check its documentation.

License

MIT

NPM DownloadsLast 30 Days