DEV Community

Cover image for Vue Composables: what are they, and how to create & use one
Bruno
Bruno

Posted on

Vue Composables: what are they, and how to create & use one

Hey there, fellow Vue enthusiasts! ๐ŸŽ‰ Ever found yourself lost in the jungle of a Vue component, overwhelmed by its tangled mess of tasks? ๐Ÿคฏ We've all been there! Picture this: you start with a simple component, but as your project blossoms, so does the complexity. Before you know it, your once tidy component has morphed into a wild beast, hard to read, test, or reuse. ๐Ÿ˜ฑ

confused

Isn't it a pain when you're constantly scrolling up and down, trying to decipher what's happening? Or worse, when you find yourself copy-pasting the same logic across multiple components? Or testing a cascading waterfall of side effects? It's like a bad dream, isn't it? Fear not, my fellow brave coder! Vue.js to the rescue with its secret weapon: composables. ๐Ÿฆธโ€โ™‚๏ธ

What Exactly Are Composables?

Think of composables as your code's trusty sidekick, always ready to swoop in and save the day! ๐Ÿฆธโ€โ™€๏ธ They're like little nuggets of wisdom, encapsulating reusable logic that you can sprinkle throughout your app. ๐ŸŒŸ In simpler terms, they're functions that return an object of goodies you can use in your Vue components. Neat, huh?

// useVuei18n.js
import { useI18n } from 'vue-i18n'

export const useVuei18n = () => {
  const { t } = useI18n()

  return { t }
}
Enter fullscreen mode Exit fullscreen mode

Now, you can sprinkle that t function magic in any component that imports the useVuei18n composable. Voila! โœจ

<template>
  <div>{{ t('hello') }}</div>
</template>

<script setup>
import { useVuei18n } from './useVuei18n'

const { t } = useVuei18n()
</script>
Enter fullscreen mode Exit fullscreen mode

Let's Dive into an Example

Ready for some hands-on learning? Let's dive into an example together! Imagine we have a component fetching users from an API and filtering them by name. Sounds simple, right? Here's how it could look:

<template>
  <div>
    <input v-model="search" @input="searchUsers" />
    <ul>
      <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const users = ref([])
const search = ref('')

const searchUsers = () => {
  // fetch users
  fetch('https://jsonplaceholder.typicode.com/users')
    .then(response => response.json())
    .then(data => {
      users.value = data.filter(user => user.name.includes(search.value))
    })
}

onMounted(searchUsers)
</script>
Enter fullscreen mode Exit fullscreen mode

The component starts simple, but as it grows, it becomes a tangled mess. Fear not! We'll rescue it with a useFetch composable, splitting responsibilities and making our code cleaner and more focused. ๐Ÿ‘Œ

// useFetch.js
import { ref } from 'vue'

export const useFetch = (url, data) => {
  const search = ref('')

  const searchUsers = () => {
    fetch(url)
      .then(response => response.json())
      .then(users => {
        data.value = users.filter(user => user.name.includes(search.value))
      })
  }

  return { search, searchUsers }
}
Enter fullscreen mode Exit fullscreen mode

Now, let's sprinkle some useFetch magic in our component:

<template>
  <div>
    <input v-model="search" @input="searchUsers" />
    <ul>
      <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useFetch } from './useFetch'

const users = ref([])

const { search, searchUsers } = useFetch('https://jsonplaceholder.typicode.com/users', users)

onMounted(searchUsers)
</script>
Enter fullscreen mode Exit fullscreen mode

We went from a component that juggles two tasks to a clean and focused setup: one task for the component and one for the composable. It's like a breath of fresh air, isn't it? ๐ŸŒฌ๏ธ And that's the beauty of composables! They keep your codebase tidy and your components happy. ๐ŸŽˆ Even your cat will thank you later. ๐Ÿˆโ€โฌ›

tom cat relieved

Composables: Behind the Scenes

Curious about how composables work under the hood? Buckle up, because we're diving into the nitty-gritty details! ๐Ÿ•ต๏ธโ€โ™‚๏ธ When you import a composable, it springs into action like a trusty sidekick ๐Ÿฆธโ€โ™‚๏ธ, executing once and caching its properties. This ensures efficiency and prevents messy side effects. Plus, composables are reactive! ๐Ÿ”„ They respond to changes, ensuring your components stay in sync with the data.

<template>
  <div>{{ $t('hello') }}</div>
</template>

<script setup>
import { useI18n } from 'vue-i

18n'

const { t: $t } = useI18n()

console.log('composable executed')
</script>
Enter fullscreen mode Exit fullscreen mode

Click that button, and watch the magic happen! The composable springs back to life, reacting to changes like a champ. ๐ŸŽ‰ Because let's face it, what's Vue.js without that sweet, sweet reactivity?

all over again, deja vu

Also, performance speaking, composables also help you avoid unnecessary re-renders. By splitting your logic into composables, you can ensure that only the relevant parts of your component re-render when the data changes. ๐Ÿš€ It would be pretty annoying if your entire component re-rendered every time you typed a single letter, wouldn't it?

When not to use Composables

While composables are a powerful tool in your Vue.js arsenal, there are times when you should think twice before using them. ๐Ÿค” For instance, if you're working on a small project or a one-off component, composables might be overkill. ๐Ÿ› ๏ธ Instead, keep it simple and stick to the basics. Also, if you're dealing with a component that's tightly coupled with its logic, you might not need a composable. ๐Ÿค Sometimes, it's okay to keep things together if they work well as a team. Take an example of a simple button component that toggles a modal. It's small, simple, and doesn't need to be split into a composable. ๐Ÿ›‘

<template>
  <button @click="toggleModal">Open Modal</button>
  <Modal v-if="showModal" @close="toggleModal" />
</template>

<script setup>
import { ref } from 'vue'

const showModal = ref(false)

const toggleModal = () => {
  showModal.value = !showModal.value
}

</script>
Enter fullscreen mode Exit fullscreen mode

If you put the toggleModal function in a composable, it would make the component more complex than it needs to be. ๐Ÿคฏ So, remember, composables are great, but use them wisely! ๐Ÿง 

Wrapping Up

And there you have it, folks! Composables: the unsung heroes of Vue.js development. ๐Ÿฆธโ€โ™€๏ธ Give it a try, and you will thank yourself later! Happy coding!๐Ÿ˜

Resources

About the Author

I'm a frontend developer and technical writer based in Portugal. I'm passionate about software engineering ๐Ÿ‘จโ€๐Ÿ’ป, and I love to explore new tools in my day-to-day. You can find me on GitHub. If you have any questions or feedback, feel free to reach out! ๐Ÿš€

Top comments (0)