[Vue] What is a Composable?
Composables are, by far, the best way to organize business logic in your Vue 3 app.
They let you extract small pieces of logic into functions that you can easily reuse repeatedly. This makes your code easier to write and read.
Since this way of writing Vue code is relatively new, you might be wondering what the best practices are when writing composables. This course will serve as your guide on how to craft solid composables that you and your team can rely on.
First, though, we need to make sure we’re on the same page. So let me take a bit to explain what, exactly, a composable is.
What is a Composable?
According to the Vue documentation, a composable is “a function that leverages Vue Composition API to encapsulate and reuse stateful logic”. If you’re not yet familiar with the composition API, or want to learn more about the advantages of using composables.
Any code that uses reactivity can be turned into a composable.
Here’s a simple example of a useMouse
composable from the Vue.js docs:
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
We define our state as refs
, then update that state whenever the mouse moves. By returning the x
and y
refs, we can use them inside of any component (or even another composable).
Here’s how we’d use this composable inside of a component:
<script setup>
import { useMouse } from './composables/mouse';
const { x, y } = useMouse();
</script>
<template>
Mouse position is at: {{ x }}, {{ y }}
</template>
As you can see, using the useMouse
composable allows us to easily reuse all of this logic. With very little extra code, we’re able to grab the mouse coordinates in our component.
Now that we’re on the same page, let’s start to think about how we should create composable inputs.
How to create composable inputs?
There are a few ways we could do it. We could use an argument for each property:
const title = useTitle('Product Page', true, '%s | My Socks Store')
We could also use an options argument:
const title = useTitle({ title: 'Product Page',
observe: true,
titleTemplate: '%s | Socks Store' })
The benefit here is we don’t have to remember the correct ordering, we know what each option does, and easier to add new options.
Or we could use a combination of both:
const title = useTitle('Product Page', { observe: true,
titleTemplate: '%s | Socks Store' })
Here we are putting the required arguments first and the other arguments are optional.
It’ll also be much easier to add new options later on. This applies both to adding new options to the composable itself, and to adding options when using the composable.
So, using an options object is great. But how do we implement that, and parse them out.
How to parse the options argument?
Here’s how you would implement the options object pattern in a composable:
export function useTitle(newTitle, options) {
const {
observe = false,
titleTemplate = '%s',
} = options;
// ...
}
Here, we can accept newTitle (our required argument), and then the last argument is the options object. The next step is to destructure the options object. By destructuring, we can access all the values, and clearly provide defaults for each possible option.