963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
2.6 KiB
2.6 KiB
name, description
| name | description |
|---|---|
| composing-stores | Store-to-store communication and avoiding circular dependencies |
Composing Stores
Stores can use each other for shared state and logic.
Rule: Avoid Circular Dependencies
Two stores cannot directly read each other's state during setup:
// ❌ Infinite loop
const useX = defineStore('x', () => {
const y = useY();
y.name; // Don't read here!
return { name: ref('X') };
});
const useY = defineStore('y', () => {
const x = useX();
x.name; // Don't read here!
return { name: ref('Y') };
});
Solution: Read in getters, computed, or actions:
const useX = defineStore('x', () => {
const y = useY();
// ✅ Read in computed/actions
function doSomething() {
const yName = y.name;
}
return { name: ref('X'), doSomething };
});
Setup Stores: Use Store at Top
import { defineStore } from 'pinia';
import { useUserStore } from './user';
export const useCartStore = defineStore('cart', () => {
const user = useUserStore();
const list = ref([]);
const summary = computed(() => {
return `Hi ${user.name}, you have ${list.value.length} items`;
});
function purchase() {
return apiPurchase(user.id, list.value);
}
return { list, summary, purchase };
});
Shared Getters
Call useStore() inside a getter:
import { useUserStore } from './user';
export const useCartStore = defineStore('cart', {
getters: {
summary(state) {
const user = useUserStore();
return `Hi ${user.name}, you have ${state.list.length} items`;
},
},
});
Shared Actions
Call useStore() inside an action:
import { useUserStore } from './user';
import { apiOrderCart } from './api';
export const useCartStore = defineStore('cart', {
actions: {
async orderCart() {
const user = useUserStore();
try {
await apiOrderCart(user.token, this.items);
this.emptyCart();
} catch (err) {
displayError(err);
}
},
},
});
SSR: Call Stores Before Await
In async actions, call all stores before any await:
actions: {
async orderCart() {
// ✅ All useStore() calls before await
const user = useUserStore()
const analytics = useAnalyticsStore()
try {
await apiOrderCart(user.token, this.items)
// ❌ Don't call useStore() after await (SSR issue)
// const otherStore = useOtherStore()
} catch (err) {
displayError(err)
}
},
}
This ensures the correct Pinia instance is used during SSR.