At my workplace I was being tasked with creating a mock chat store for internal local dev work, and while doing so I made few notes about Vue (I had some experience, but not with hooks), So this is just my obsidian notes, I hope its useful to you :)
Table of Contents
- Ref and Reactive References
- Watch and Reactivity
- Pinia Store Integration
- Practical Examples
- Best Practices
- Common Gotchas
Ref and Reactive References
What is Ref?
ref is Vue's way of making primitive values reactive. It wraps the value in a reactive object with a .value property.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import { ref } from 'vue'
export const useMyStore = defineStore( 'my-store' , () => {
const count = ref<number>(0)
function increment() {
count .value++
}
return {
count ,
increment
}
})
|
Copy after login
Types of Refs in Stores
1 2 3 4 5 6 7 8 9 10 11 | const isLoading = ref<boolean>(false)
const messages = ref<Message[]>([])
const currentUser = ref<User | null>(null)
const selectedId = ref<string | undefined>(undefined)
|
Copy after login
Watch and Reactivity
Basic Watch Usage
1 2 3 4 5 6 7 8 9 10 | import { watch, ref } from 'vue'
export const useMyStore = defineStore( 'my-store' , () => {
const messages = ref<Message[]>([])
watch(messages, (newMessages, oldMessages) => {
console.log( 'Messages changed:' , newMessages)
})
})
|
Copy after login
Watch Options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | watch(messages, (newMessages) => {
}, { immediate: true })
watch(messages, (newMessages) => {
}, { deep: true })
watch(
[messages, selectedId],
([newMessages, newId], [oldMessages, oldId]) => {
}
)
|
Copy after login
Pinia Store Integration
Store Structure with Refs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | export const useMyStore = defineStore( 'my-store' , () => {
const items = ref<Item[]>([])
const isLoading = ref(false)
const error = ref<Error | null>(null)
const itemCount = computed(() => items.value.length)
const fetchItems = async () => {
isLoading.value = true
try {
items.value = await api.getItems()
} catch (e) {
error.value = e as Error
} finally {
isLoading.value = false
}
}
return {
items,
isLoading,
error,
itemCount,
fetchItems
}
})
|
Copy after login
Composing Stores
1 2 3 4 5 6 7 8 9 10 11 12 | export const useMainStore = defineStore( 'main-store' , () => {
const otherStore = useOtherStore()
watch(
() => otherStore.someState,
(newValue) => {
}
)
})
|
Copy after login
Practical Examples
Auto-refresh Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | export const useChatStore = defineStore( 'chat-store' , () => {
const messages = ref<Message[]>([])
const refreshInterval = ref<number | null>(null)
const isRefreshing = ref(false)
watch(isRefreshing, (shouldRefresh) => {
if (shouldRefresh) {
startAutoRefresh()
} else {
stopAutoRefresh()
}
})
const startAutoRefresh = () => {
refreshInterval.value = window.setInterval(() => {
fetchNewMessages()
}, 5000)
}
const stopAutoRefresh = () => {
if (refreshInterval.value) {
clearInterval(refreshInterval.value)
refreshInterval.value = null
}
}
return {
messages,
isRefreshing,
startAutoRefresh,
stopAutoRefresh
}
})
|
Copy after login
Loading State Management
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | export const useDataStore = defineStore( 'data-store' , () => {
const data = ref<Data[]>([])
const isLoading = ref(false)
const error = ref<Error | null>(null)
watch(isLoading, (loading) => {
if (loading) {
} else {
}
})
watch(error, (newError) => {
if (newError) {
}
})
})
|
Copy after login
Best Practices
1. Ref Initialisation
1 2 3 4 5 | const data = ref()
const data = ref<string[]>([])
|
Copy after login
2. Watch Cleanup
1 2 3 4 5 6 7 8 9 10 | watch(source, () => {
const timer = setInterval(() => {}, 1000)
})
watch(source, () => {
const timer = setInterval(() => {}, 1000)
return () => clearInterval(timer)
})
|
Copy after login
3. Computed vs Watch
1 2 3 4 5 6 7 | watch(items, (newItems) => {
itemCount.value = newItems.length
})
const itemCount = computed(() => items.value.length)
|
Copy after login
4. Store Organization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | export const useStore = defineStore( 'store' , () => {
const data = ref<Data[]>([])
const isLoading = ref(false)
const isEmpty = computed(() => data.value.length === 0)
watch(data, () => {
})
const fetchData = async () => {
}
return {
data,
isLoading,
isEmpty,
fetchData
}
})
|
Copy after login
Common Gotchas
-
Forgetting .value
1 2 3 4 5 6 | const count = ref(0)
count ++
count .value++
|
Copy after login
-
Watch Timing
1 2 3 4 5 | watch(source, () => {})
watch(source, () => {}, { immediate: true })
|
Copy after login
-
Memory Leaks
1 2 3 4 5 6 7 8 9 10 11 | const store = useStore()
setInterval(() => {
store.refresh()
}, 1000)
const intervalId = setInterval(() => {
store.refresh()
}, 1000)
onBeforeUnmount(() => clearInterval(intervalId))
|
Copy after login
Remember: Always consider cleanup, type safety, and proper organization when working with refs and watches in Pinia stores
The above is the detailed content of Understanding Vue Reactivity with Pinia Stores. For more information, please follow other related articles on the PHP Chinese website!