Store Composition

Preview — 3 of 10 questions

What is the difference between Options syntax and Setup syntax for defineStore?

javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

// Setup store syntax
export const useUserStore = defineStore('user', () => {
  // State — refs
  const user = ref<User | null>(null)
  const isLoading = ref(false)
  const token = ref<string | null>(localStorage.getItem('token'))

  // Getters — computed
  const isAuthenticated = computed(() => !!user.value)
  const fullName = computed(() =>
    user.value ? `${user.value.firstName} ${user.value.lastName}` : ''
  )

  // Actions — functions (can be async)
  async function login(credentials: Credentials) {
    isLoading.value = true
    try {
      const { data } = await api.login(credentials)
      user.value = data.user
      token.value = data.token
      localStorage.setItem('token', data.token)
    } finally {
      isLoading.value = false
    }
  }

  function logout() {
    user.value = null
    token.value = null
    localStorage.removeItem('token')
  }

  // Must return all the state/getters/actions
  return { user, isLoading, token, isAuthenticated, fullName, login, logout }
})
ASetup stores use a function returning reactive state/computed/methods — similar to <script setup> — giving more flexibility and better TypeScript inference
BSetup stores are only available in Vue 3.3+; Options stores work in Vue 2 and 3
COptions stores support SSR while Setup stores do not
DSetup stores cannot have actions — only computed properties

How do you create a Pinia plugin?

javascript
import { createPinia } from 'pinia'
import type { PiniaPluginContext } from 'pinia'

// Example: Local storage persistence plugin
function localStoragePlugin({ store }: PiniaPluginContext) {
  const storeId = store.$id

  // Rehydrate state from localStorage on store creation
  const savedState = localStorage.getItem(`pinia-${storeId}`)
  if (savedState) {
    store.$patch(JSON.parse(savedState))
  }

  // Persist state on every change
  store.$subscribe((mutation, state) => {
    localStorage.setItem(`pinia-${storeId}`, JSON.stringify(state))
  }, { detached: true })
}

// Example: Add $api property to every store
function apiPlugin({ store }: PiniaPluginContext) {
  store.$api = markRaw(apiClient) // markRaw prevents proxy wrapping
}

// TypeScript augmentation for custom properties
declare module 'pinia' {
  export interface PiniaCustomProperties {
    $api: typeof apiClient
  }
}

// Register plugins
const pinia = createPinia()
pinia.use(localStoragePlugin)
pinia.use(apiPlugin)
ACall pinia.use() with a function that receives { pinia, app, store, options }
BExtend the PiniaPlugin class and register it with app.use
CDefine a plugin in the store options using plugins: [myPlugin]
DUse createPinia({ plugins: [myPlugin] })

What is the correct way to configure pinia-plugin-persistedstate for selective persistence?

javascript
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    user: null,
    token: null,
    preferences: { theme: 'dark', language: 'en' },
    sessionData: {} // Should NOT be persisted
  }),
  actions: { ... },
  persist: {
    // Persist only specific paths.
    // NOTE: in pinia-plugin-persistedstate v3+ `paths` was renamed to `pick`
    // (and an `omit` counterpart was added): pick: ['token', 'preferences']
    paths: ['token', 'preferences'],
    // Use sessionStorage instead of localStorage
    storage: sessionStorage,
    // Custom serializer
    serializer: {
      serialize: (value) => JSON.stringify(value),
      deserialize: (value) => JSON.parse(value)
    },
    // Key in storage
    key: 'my-app-user',
    // Custom before-restore hook
    beforeRestore: (ctx) => {
      console.log('Restoring store:', ctx.store.$id)
    }
  }
})

// Setup stores also support persist
export const useAuthStore = defineStore('auth', () => {
  const token = ref<string | null>(null)
  return { token }
}, {
  persist: { paths: ['token'], storage: localStorage }
})
ASet persist: true in the store — all state is persisted automatically
BCall store.$persist() manually after state changes
CUse the persist option in defineStore with granular configuration for paths, storage, and serialization
DConfigure persistence in createPinia({ persist: { ... } })

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.