We use cookies to enhance your experience on the site
CodeWorlds

Store Composition

At NOVA LAB, different station systems must work together - the oxygen system communicates with the alarm system, and the navigation system with the communication system. Similarly in Pinia - stores can import and use other stores.

Store Using Another Store

1// stores/auth.js
2import { defineStore } from 'pinia'
3import { ref, computed } from 'vue'
4
5export const useAuthStore = defineStore('auth', () => {
6  const user = ref(null)
7  const token = ref(null)
8
9  const isAuthenticated = computed(() => !!token.value)
10  const userName = computed(() => user.value?.name || 'Guest')
11
12  async function login(credentials) {
13    const res = await fetch('/api/login', {
14      method: 'POST',
15      headers: { 'Content-Type': 'application/json' },
16      body: JSON.stringify(credentials)
17    })
18    const data = await res.json()
19    token.value = data.token
20    user.value = data.user
21  }
22
23  function logout() {
24    user.value = null
25    token.value = null
26  }
27
28  return { user, token, isAuthenticated, userName, login, logout }
29})
1// stores/missions.js - uses auth store
2import { defineStore } from 'pinia'
3import { ref } from 'vue'
4import { useAuthStore } from './auth'
5
6export const useMissionsStore = defineStore('missions', () => {
7  const missions = ref([])
8
9  async function fetchMissions() {
10    // Use auth store to get the token
11    const authStore = useAuthStore()
12
13    if (!authStore.isAuthenticated) {
14      throw new Error('Must be logged in')
15    }
16
17    const res = await fetch('/api/missions', {
18      headers: {
19        'Authorization': `Bearer ${authStore.token}`
20      }
21    })
22
23    missions.value = await res.json()
24  }
25
26  return { missions, fetchMissions }
27})

Mutual Store Dependencies

Stores can use each other, but call

useStore()
inside actions (not at the top of the setup function) to avoid circular dependency issues:

1// stores/notifications.js
2import { defineStore } from 'pinia'
3import { ref } from 'vue'
4
5export const useNotificationStore = defineStore('notifications', () => {
6  const notifications = ref([])
7
8  function add(message, type = 'info') {
9    notifications.value.push({
10      id: Date.now(),
11      message,
12      type,
13      timestamp: new Date()
14    })
15  }
16
17  function remove(id) {
18    notifications.value = notifications.value.filter(n => n.id !== id)
19  }
20
21  return { notifications, add, remove }
22})
23
24// stores/resources.js - uses notifications
25import { useNotificationStore } from './notifications'
26
27export const useResourceStore = defineStore('resources', () => {
28  const oxygen = ref(100)
29
30  function consumeOxygen(amount) {
31    oxygen.value -= amount
32
33    if (oxygen.value < 20) {
34      // Call useStore INSIDE action
35      const notifStore = useNotificationStore()
36      notifStore.add('Oxygen level critical!', 'danger')
37    }
38  }
39
40  return { oxygen, consumeOxygen }
41})

Multi-Store Architecture

It's recommended to create many small, specialized stores instead of one large one:

1stores/
2├── auth.js         # User authorization
3├── resources.js    # Station resources (oxygen, water, energy)
4├── crew.js         # Crew data
5├── missions.js     # Missions and tasks
6├── notifications.js # Notification system
7└── settings.js     # Application settings

Each store is responsible for one "module" of the application - just as each NOVA LAB station module has its own function.

Go to CodeWorlds