Daniel Kelly
Teacher @ Vue School
Full Stack developer (10 years)
Husband and Father
#1 Training Platform for Vue.js
750+ Video Lessons
140,000 users
Alex Kyriakidis
Daniel Kelly
Debbie O'Brien
Maria Lamardo
Roman Kuba
Filip Rakowski
Lydia Hallie
Rolf Haug
Workshops
Vue Corporate Training
📺
Vue Video
Courses
👨🏫
Live Workshops
Alex Kyriakidis
Founder of Vue School
Author of The Majesty of Vue.js
Vue.js Contributor
State Management in Vue.js with Pinia
Workshop Structure
Workshop Structure
👨🏫 Instruction
💬 Questions
👩💻 Hands-on Exercises
(10 - 20 mins)
(0 - 10 mins)
(15 - 30 mins)
📺 Solution
(5 - 10 mins)
Workshop Goal
Master Pinia
🎉 Have fun
- What is Pinia?
- Pinia State
- Pinia Actions
- Pinia Getters
- Using Stores in Other Stores
- Subscribe to Pinia Stores
- Pinia Plugins
- Advanced Concepts
Workshop Outline
Buddy System
🧑🤝🧑👭👬
✅ 🛑 👨🏫👩🏫
Meet Your Team
🧑🤝🧑👭👬
💬
💬
💬
What is Pinia?
1
What is Pinia?
Global state management solution
- Created by Eduardo San Martin Morote
What is Pinia?
Global state management solution
- Created by Eduardo San Martin Morote
- An experiment to flesh out the next version of Vuex
What is Pinia?
Global state management solution
- Created by Eduardo San Martin Morote
- An experiment to flesh out the next version of Vuex
- Became the recommended global state management solution in the latest official Vue.js docs
What is Pinia?
Global state management solution
What is Pinia?
Global state management solution
What is Pinia?
Global state management solution
https://vuejs.org/guide/scaling-up/state-management.html#pinia
What is Global State Management?
What is Global State Management?
Local State Management
<script setup>
import {ref} from "vue"
const count = ref(0)
</script>
<script>
export default {
data(){
return {
count: 0
}
}
}
</script>
Composition API
Options API
Props
Events
What is Global State Management?
What is Global State Management?
What is Global State Management?
What is Global State Management?
NOT a replacement for props, events, and local data
Local vs Global State
How do I know which is which?
- Data needed throughout page
- Data needed across multiple pages
- Data is application specific
- Specific to component instance
- Component is reusable
Global State
Local Data
Local vs Global State
How do I know which is which?
Examples of local data
<!-- LoginForm.vue -->
<script setup>
import { ref } from "vue";
const form = ref({
username: "",
password: ""
})
</script>
<template>
<form @submit="$emit('login', form)">
<label>
Username
<input v-model="form.username">
</label>
<label>
Password
<input v-model="form.password">
</label>
</form>
</template>
- Form data
Local vs Global State
How do I know which is which?
Examples of local data
<!--TwitterFeed.vue-->
<script setup>
import { ref } from "vue";
const loading = ref(false);
function loadTweets(){
loading.value = true;
// load the data...
loading.value = false;
}
//...
</script>
<template>
<!-- tweets...-->
<AppSpinner v-if="loading"/>
</template>
- Form data
- Loading State
Local vs Global State
How do I know which is which?
Examples of global state
<!-- AppHeader.vue -->
<template>
<!--...-->
<a class="/me">
{{ user.name }}
</a>
</template>
- Authenticated user
<!-- MyPosts.vue -->
<script>
const fetchPosts = ()=>{
fetch(`https://myendpoint.com/user-posts/${user.id}`)
}
//...
</script>
<!-- Profile.vue -->
<!-- ProfileEditor.vue -->
<!-- AppFooter.vue -->
<!-- etc -->
Local vs Global State
How do I know which is which?
Examples of global state
<!-- PostHero.vue -->
<template>
<!--...-->
<div class="hero">
{{ post.title }}
</div>
</template>
- Authenticated user
- Blog post
<!-- PostShow.vue -->
<script>
const fetchPost = ()=>{
fetch(`https://myendpoint.com/posts/${post.id}`)
}
//...
</script>
<!-- PostByLine.vue -->
<!-- PostComments.vue -->
<!-- PostBody.vue -->
<!-- etc -->
What about Vuex?
What about Vuex?
Pinia provides several advantages:
- Pinia is modular by default (great for organization and code splitting)
- Pinia removes mutations
- Pinia is more intuitive
- Pinia has full type support for TypeScript
- We'll see examples of all of these throughout the workshop
What about Vuex?
https://vueschool.io/articles/vuejs-tutorials/how-to-migrate-from-vuex-to-pinia/
Can I use it with Vue 2?
Can I use it with Vue 2?
Yes!
- (< 2.7) Must install the @vue/composition-api plugin
- There are a few small caveats
- Can use with composition API or Options API
- During this workshop, we'll focus on Composition API
How to Install Pinia
How to Install Pinia
npm init vue@3
for a new project
How to Install Pinia
npm install pinia
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
createApp(App)
.use(createPinia())
.mount("#app");
in an existing project
Create Your First Store
Create Your First Store
Pinia is modular by default
Create Your First Store
Pinia is modular by default
Create Your First Store
Pinia is modular by default
Store
Posts
Store
Users
Users
Store
Comments
Blog Application
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
- a store is a regular .js or .ts file
- lives in a "stores" directory by convention
- use defineStore from Pinia define file as a store
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
defineStore('PostStore')
- first argument is store name
- name is required
- this name will show in the devtools
- My preference to name it the same as the filename
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
defineStore('PostStore', {
// state
// actions
// getters
})
second argument is store options object
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
defineStore('PostStore', () => {
return {
// data
// functions
// etc
}
})
second argument can also be a function similar to component setup()
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
export const usePostStore = defineStore('PostStore', {
// state
// actions
// getters
})
- expose the store by exporting it
- convention to prefix with `use`
Create Your First Store
// stores/PostStore.js
import { defineStore } from 'pinia'
export const usePostStore = defineStore('PostStore', {
// state
// actions
// getters
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(usePostStore, import.meta.hot));
}
support HMR but must provide a snippet
Create Your First Store
// App.vue
<script setup>
import { usePostStore } from "@/stores/PostStore"
const postStore = usePostStore();
</script>
use the store by importing the use function and calling it
Create Your First Store
Questions?
What We're Buliding
What We're Buliding
What We're Buliding
Let's take a look at:
- The boilerplate code
- and the existing app in the browser
Assignment #1 (15 mins)
👩💻👨🏽💻
Pinia State
2
Define Pinia State
// stores/ProductStore.ts
import { defineStore } from "pinia";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {};
},
});
Must be a function
- Allows Pinia to work on both client side and server side
- the arrow function is recommended for full type inference
Define Pinia State
// stores/ProductStore.ts
import { defineStore } from "pinia";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
name: "The Pineapple Stand",
products: [
"Plain Ol' Pineapple",
"Dried Pineapple",
"Pineapple Gum",
"Pineapple T-Shirt",
],
isAwesome: true,
};
},
});
Access Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
const productStore = useProductStore();
console.log(productStore.name) // "The Pineapple Stand"
</script>
...
State available as property on store
Access Pinia State
State is TypeSafe
Access Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
const { name } = useProductStore();
console.log(name) // "The Pineapple Stand"
</script>
...
⚠️ Name is no longer reactive
Can de-structure state from store
Access Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
import { storeToRefs } from "pinia";
const { name } = storeToRefs(useProductStore());
console.log(name.value) // "The Pineapple Stand"
</script>
...
When de-structuring convert store to refs to maintain reactivity
Update Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
import { storeToRefs } from "pinia";
const { name } = storeToRefs(useProductStore());
name.value = "Hello new name";
</script>
State can be directly updated
Update Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
import { storeToRefs } from "pinia";
const productStore = useProductStore();
productStore.name = "Hello new name";
</script>
No need for .value if you don't de-destructure
Update Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
import { storeToRefs } from "pinia";
const { name } = storeToRefs(useProductStore());
</script>
<template>
<input v-model="name" type="text" />
</template>
Use with v-model is easy!
Update Pinia State
Update Pinia State
// stores/App.vue
<script setup>
import { useProductStore } from "./stores/ProductStore";
import { storeToRefs } from "pinia";
const { name: newName } = storeToRefs(useProductStore());
</script>
Can rename de-structured state
Pinia State
Useful feature you don't get if you roll your own stores with vanilla composition API.
Pinia State
Comes with some built in helpers
store.$reset()
// acccess the entire state or
// set it all at once
store.$state
Questions?
Assignment #2 (20 mins)
👩💻👨🏽💻
15 Minute Break
☕️
Pinia Actions
3
Pinia Actions
What are they?
- Methods for mutating the store's state
- can think of them like component methods but for the store
- provide standardized and named mechanisms for mutating the state
- are great for feedback in the devtools
- consolidate business logic
- can be asynchronous or synchronous
Pinia Actions
import { defineStore } from "pinia";
import products from "@/data/products.json";
export const useProductStore = defineStore("ProductStore", {
state: //...
actions:{
fill(){}
}
});
Define actions as methods on the actions option
Pinia Actions
import { defineStore } from "pinia";
export const useProductStore = defineStore("ProductStore", {
state: ()=>{
return {
products:[],
}
},
actions:{
async fill(){
const res = await fetch('my_api_endpoint/products');
this.products = await res.json();
}
}
});
access state with `this`
Great for filling state with initial data
Pinia Actions
import { defineStore } from "pinia";
export const useProductStore = defineStore("ProductStore", {
state: ()=>{
return {
products:[],
}
},
actions:{
async someOtherAction(){},
async fill(){
const res = await fetch('my_api_endpoint/products');
this.products = await res.json();
this.someOtherAction()
}
}
});
access other actions with `this`
Great for filling state with initial data
Pinia Actions
State is fully typed on `this` within actions
Pinia Actions
Call actions in components as store methods
<script setup>
const productStore = useProductStore();
productStore.fill();
</script>
Pinia Actions
Or de-structure it from the store
<script setup>
const { fill } = useProductStore();
fill();
</script>
Pinia Actions
You CANNOT get actions when using storeToRefs
<script setup>
const { fill } = storeToRefs(useProductStore());
fill(); // Error
</script>
❌
won't work
Pinia Actions
import { defineStore } from "pinia";
export const useCartStore = defineStore("CartStore", {
state: () => {
return {
items: [],
};
},
actions: {
addItem(itemId, count) {
// set the count for the proper item in the state above
},
},
});
Useful for updating state based on user interaction
// App.vue
<button @click="addItem(product.id, $event)">Add Product to Cart</button>
Pinia Actions
Mutations grouped in the devtools
Pinia $patch
Alternate way of grouping mutations to state
productStore.$patch({
name: "Vue Conf Toronto",
location: "Toronto, Canada",
});
Pinia $patch
Alternate way of grouping mutations to state
Pinia $patch
Can also use a callback function
cartStore.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1 })
state.hasChanged = true
})
Questions?
Assignment #3 (20 mins)
👩💻👨🏽💻
Pinia Getters
4
Pinia Getters
What are they?
equivalent of computed props on a component
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count() {
return this.products.length;
},
},
actions: {
//...
},
});
access state with `this`
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count(): number {
return this.products.length;
},
},
actions: {
//...
},
});
access state with `this`
must explicitly type the return
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count: (state) => {
return state.products.length;
},
},
actions: {
//...
},
});
access state with `state`
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count: (state) => state.products.length,
},
actions: {
//...
},
});
encourages single
line arrow functions
No need to explicitly type return
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count: (state) => state.products.length,
doubleCount(): number {
return this.count * 2;
},
},
actions: {
//...
},
});
access other
getters on `this`
Pinia Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count: (state) => state.products.length,
doubleCount: (state) => state.count * 2,
productByName: (state) => (name) => {
return state.products.find((product) => product.name === name);
},
},
});
accept arguments
by returning a function
Dynamic Getters
// ProductStore.ts
import { defineStore } from "pinia";
import type { Product } from "@/types";
export const useProductStore = defineStore("ProductStore", {
state: () => {
return {
products: [] as Product[],
};
},
getters: {
count: (state) => state.products.length,
doubleCount: (state) => state.count * 2,
productByName(state) {
return function (name) {
return state.products.find((product) => product.name === name);
};
},
},
});
accept arguments
by returning a function
Pinia Getters
Dynamic Getters
Pinia Getters
// App.vue
<script setup>
const productStore = useProductStore();
console.log(productStore.count) // 4
</script>
Access getters as a property on the store
Pinia Getters
// App.vue
<script setup>
import { storeToRefs } from "pinia";
const { count } = storeToRefs(useProductStore());
console.log(count.value) // 4
</script>
Can de-structure getters from store but must use `storeToRefs`
Questions?
Assignment #4 (20 mins)
👩💻👨🏽💻
Using Stores in Other Stores
5
Using Stores in Other Stores
// CartStore.ts
import { defineStore } from "pinia";
import { useProductStore } from "./ProductStore";
export const useCartStore = defineStore("CartStore", {
// ...
getters: {
allProducts(){
const productStore = useProductStore();
return productStore.products
}
},
//...
});
Use state and getters from another store in a getter or an action
Using Stores in Other Stores
// CartStore.ts
import { defineStore } from "pinia";
import { useProductStore } from "./ProductStore";
export const useCartStore = defineStore("CartStore", {
//...
actions:{
reloadProducts(){
const productStore = useProductStore();
return productStore.fill()
}
}
//...
});
Use actions from another store in an action
Using Stores in Other Stores
// CartStore.ts
import { defineStore } from "pinia";
import { useProductStore } from "./ProductStore";
❌ const productStore = useProductStore();
export const useCartStore = defineStore("CartStore", {
//...
actions:{
reloadProducts(){
return productStore.fill()
}
}
//...
});
Use actions from another store in an action
Using Stores in Other Stores
// CartStore.ts
import { defineStore } from "pinia";
import { useProductStore } from "./ProductStore";
❌ const productStore = useProductStore();
export const useCartStore = defineStore("CartStore", {
//...
actions:{
reloadProducts(){
return productStore.fill()
}
}
//...
});
Use actions from another store in an action
Questions?
Assignment #5 (15 mins)
👩💻👨🏽💻
Subscribe to Pinia Stores
6
Subscribe to Pinia Stores
- watch state for changes
- watch actions for calls
- and perform side affects
Subscribe to Pinia Stores
- watch state for changes
- watch actions for calls
- and perform side affects
- measuring how long your actions take to run
- triggering user notifications
- logging errors to 3rd party services
Subscribe to Pinia Stores
someStore.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
console.log(name, store, args, after, onError);
}
);
Subscribe to actions
Subscribe to Pinia Stores
someStore.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
if(name === 'fill'){
//... do the things here
}
}
);
Use conditional to run on select actions
Subscribe to Pinia Stores
someStore.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
after( result =>{
console.log(`the action is complete and returned ${result}`)
})
onError(error =>{
console.log(`the action failed and the error thrown is ${error}`)
})
}
);
Example of after and onError
Subscribe to Pinia Stores
someStore.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
after( result =>{
console.log(`the action is complete and returned ${result}`)
})
onError(error =>{
console.log(`the action failed and the error thrown is ${error}`)
})
}
);
Example of after and onError
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
// same as cartStore.$id
mutation.storeId
// only available with mutation.type === 'patch object'
mutation.payload // patch object passed to $patch()
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
someStore.myState = "something else"
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
someStore.$patch({
myState: "something else",
otherState: true
})
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
someStore.$patch((state)=>{
state.myState = "something else"
})
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
// same as cartStore.$id
mutation.storeId
// only available with mutation.type === 'patch object'
mutation.payload // patch object passed to $patch()
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
// same as cartStore.$id
mutation.storeId
defineStore("someStore", {/*...*/})
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
// 'direct' | 'patch object' | 'patch function'
mutation.type
// same as cartStore.$id
mutation.storeId
// only available with mutation.type === 'patch object'
mutation.payload // patch object passed to $patch()
})
Subscribing to the state
Subscribe to Pinia Stores
someStore.$subscribe((mutation, state) => {
localStorage.setItem('myState', JSON.stringify(state))
})
Subscribing to the state
Questions?
Assignment #6 (25 mins)
👩💻👨🏽💻
Pinia Plugins
7
Pinia Plugins
Just like Vue has plugins to quickly add advanced functionality...
Pinia Plugins
...so does Pinia
Pinia Plugins
One advantages of the standardization provided by an official store solution over vanilla CAPI store
Pinia Plugins
What can they do?
- Add new properties to stores
- Add new options when defining stores
- Add new methods to stores
- Wrap existing methods
- Change or even cancel actions
- Implement side effects like Local Storage
Pinia Plugins
How to build
//PiniaLocalStoragePlugin.ts
export function PiniaLocalStoragePlugin({
pinia,
app,
store,
options
}) {
}
// the pinia created with `createPinia()`
// the current app created with `createApp()` (Vue 3 only)
// the store the plugin is augmenting
// the options object defining the store passed to `defineStore()`
Pinia Plugins
How to build
//PiniaLocalStoragePlugin.ts
export function PiniaLocalStoragePlugin({
pinia,
app,
store,
options
}) {
const localStorageKey = `PiniaStore_${store.$id}`;
store.$subscribe((mutation, state) => {
localStorage.setItem(localStorageKey, JSON.stringify(state));
});
const savedState = localStorage.getItem(localStorageKey);
if (savedState) {
store.$state = JSON.parse(savedState);
}
}
Pinia Plugins
Applies to all stores by default
//PiniaLocalStoragePlugin.ts
export function PiniaLocalStoragePlugin({
pinia,
app,
store,
options
}) {
const localStorageKey = `PiniaStore_${store.$id}`;
store.$subscribe((mutation, state) => {
localStorage.setItem(localStorageKey, JSON.stringify(state));
});
const savedState = localStorage.getItem(localStorageKey);
if (savedState) {
store.$state = JSON.parse(savedState);
}
}
Pinia Plugins
Making it opt-in
//CartStore.ts
export const useCartStore = defineStore("CartStore", {
localStorage: true,
state: ()=>{ /*...*/ },
getters: {/*...*/}
})
Pinia Plugins
Making it opt-in
//PiniaLocalStoragePlugin.ts
export function PiniaLocalStoragePlugin({
pinia,
app,
store,
options
}) {
if (!options.localStorage) return;
const localStorageKey = `PiniaStore_${store.$id}`;
store.$subscribe((mutation, state) => {
localStorage.setItem(localStorageKey, JSON.stringify(state));
});
const savedState = localStorage.getItem(localStorageKey);
if (savedState) {
store.$state = JSON.parse(savedState);
}
}
Pinia Plugins
Type the new option
import "pinia";
declare module "pinia" {
export interface DefineStoreOptionsBase<S, Store> {
// allow defining a boolean
// for local storeage plugin
localStorage?: boolean;
}
}
Pinia Plugins
extend the DefineStoreOptionsBase
// main.ts
//...
import { PiniaLocalStoragePlugin } from "./plugins/...";
const pinia = createPinia()
.use(PiniaLocalStoragePlugin);
createApp(App)
.use(pinia)
.mount("#app");
Pinia Plugins
Use the plugin
//PiniaAxiosPlugin.ts
import axios from "axios";
export function PiniaAxiosPlugin({
pinia,
app,
store,
options
}) {
store.axios = axios;
}
Pinia Plugins
Another example: adding axios
// ProductStore.ts
export const useProductStore = defineStore("ProductStore", {
//...
actions: {
async fill() {
const res = await this.axios.get("/products.json");
this.products = res.data;
},
},
});
Pinia Plugins
Another example: adding axios
//PiniaAxiosPlugin.ts
import axios from "axios";
import { markRaw } from "vue";
export function PiniaAxiosPlugin({
pinia,
app,
store,
options
}) {
store.axios = markRaw(axios);
}
Pinia Plugins
Another example: adding axios
Pinia Plugins
Typing axios on stores
import "pinia";
import type { Axios } from "axios";
declare module "pinia" {
export interface PiniaCustomProperties {
axios: Axios;
}
}
Pinia Plugins
Typing axios on stores
Pinia Plugins
3rd party pinia plugins
- There is no awesome Pinia repo
- Can search npm for Pinia plugins
Questions?
Assignment #7 (25 mins)
👩💻👨🏽💻
Defining a Store Using a Setup Function
8
Defining a Store Using a Setup Function
//CounterStore.ts
export const useCounterStore = defineStore('CounterStore', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
Defining a Store Using a Setup Function
Why?
Defining a Store Using a Setup Function
Why?
- style preference
- can watch state from within the store
- consistent syntax with components
- Can have private actions or getters
Defining a Store Using a Setup Function
Limitations
- No this, no $patch(), $reset(), etc
- Must return ALL state properties owned by the store
Defining a Store Using a Setup Function
//CounterStore.ts
export const useCounterStore = defineStore('CounterStore', () => {
const count = ref(0)
function increment() {
count.value++
}
watch(count, ()=>{
// save some data to the server or whatever
})
return { count, increment }
})
Defining a Store Using a Setup Function
//CounterStore.ts
import { watchDebounced } from '@vueuse/core'
export const useCounterStore = defineStore('CounterStore', () => {
const count = ref(0)
function increment() {
count.value++
}
watchDebounced(count, ()=>{
// save some data to the server or whatever
}, { debounce: 500 })
return { count, increment }
})
Questions?
Assignment #8 (25 mins)
👩💻👨🏽💻
Q&A
Pinia: The Enjoyable Vue Store
Other Great Courses Too!
Black Friday Special
Workshop
Vue.js Fundamentals
TypeScript + Vue Workshop
Vue 3 Composition API Workshop
Nuxt 3 Fundamentals Workshop
Vue.js Certification
Thanks!
1. Pinia Workshop
By Daniel Kelly
1. Pinia Workshop
- 2,333