Composing Stores

Composing stores is about having stores that use each other and there is one rule to follow:

If two or more stores use each other, they cannot create an infinite loop through getters or actions. They cannot both directly read each other state in their setup function:

const useX = defineStore("x", () => {
  const y = useY()

  // ❌ This is not possible because y also tries to read x.name
  y.name

  function doSomething() {
    // ✅ Read y properties in computed or actions
    const yName = y.name
    // ...
  }

  return {
    name: ref("I am X")
  }
})

const useY = defineStore("y", () => {
  const x = useX()

  // ❌ This is not possible because x also tries to read y.name
  x.name

  function doSomething() {
    // ✅ Read x properties in computed or actions
    const xName = x.name
    // ...
  }

  return {
    name: ref("I am Y")
  }
})

Nested stores

Note that if one store uses another store, there is no need to create a new store in a separate file, you can directly import it. Think of it as nesting.

You can call useOtherStore() at the top of any getter or action:

import { useUserStore } from "./user"

export const cartStore = defineStore("cart", {
  getters: {
    // ... other getters
    summary(state) {
      const user = useUserStore()

      return `Hi ${user.name}, you have ${state.list.length} items in your cart. It costs ${state.price}.`
    }
  },

  actions: {
    purchase() {
      const user = useUserStore()

      return apiPurchase(user.id, this.list)
    }
  }
})

Shared Getters

You can simply call useOtherStore() inside a getter:

import { defineStore } from "react-mise"
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 in your cart. It costs ${state.price}.`
    }
  }
})

Shared Actions

The same applies to actions:

import { defineStore } from "react-mise"
import { useUserStore } from "./user"

export const useCartStore = defineStore("cart", {
  actions: {
    async orderCart() {
      const user = useUserStore()

      try {
        await apiOrderCart(user.token, this.items)
        // another action
        this.emptyCart()
      } catch (err) {
        displayError(err)
      }
    }
  }
})