Recommended way to send data from Store to Components

Hi, It’s my first question here so :bear: with me.

I’m using Vue 3 + Pinia + Axios and I currently have these 3 layers in focus:

  • API layer (a bunch of methods making axios requests
  • Store layer (using Pinia)
  • Components

Currently in my components if I want to get users (which are grouped) I do:

await usersStore.getAll(groupId); 
...
usersStore.all[groupId].users; // Access them directly or use a store getter when needed
...
watch(
  () => groupId,
  async (newGroupId) => {
    await usersStore.getAll(newGroupId);
  }
);

I don’t like this because I don’t want the component to care about if those users are loaded or not. The store (or a different layer) should handle this.
In my components I would simply like to do getUsers(groupId) and just use them.

I could return them directly in the store method but the getUsers is async (because it calls the API layer) and I can’t use that in various places like computed methods or directly inside v-bind attributes.

Is there a better way to do this that I’m unaware of?

You could create a useUsers composable which would take care of loading users, reporting any errors if there are any and also give you a loading status. Then in your component you could simply “use” the useUsers composable and get the users without having to worry about the implementation details.

https://vuejs.org/guide/reusability/composables.html

// useUsers.js|ts
export function useUsers() {
  let users = $ref([])
  let error = $ref('')
  let loading = $ref(false)

  const getUsers = async () {
    isLoading = true

    try {
        users = await usersApi.getUsers()
    } catch (error) {
        error = 'Something went wrong!'
    } finally {
        isLoading = false
    }
  }

  getUsers()

  return $$({ users, loading, error, getUsers})
}

Then in your component you can just use the users like this:

<script setup>
    import { useUsers } from 'useUsers'

    const { users, getUsers } = useUsers()
</script>
2 Likes

That’s it!
Composables are exactly what I needed, thanks a lot!

I really appreciate it.