Vue Composables is a very helpful tool when developing Vue applications. They provide developers an easy way to reuse logic in our applications. In addition to allowing “Stateless” logic (things like formatting or routine calculation), composables also give us the ability to reuse state logic throughout the app.
Before diving into the tutorial below, I would like to say that there are documents for Wu Really Nice Page on Compositable The basics really explain well and you will find 90 % of the way there. I am writing this article because I think the examples in the documents can be a little deeper to tell how things can work within a composingable. I will repeat some information from the documents, but I will also provide an example of a more complex composing composing.
Here’s what we will cover is:
Why use composables?
Composites allow you to reuse state logic in your apps. Whenever there is logic that is used in more than two places, we usually want to draw this logic into its own function. Most of the time, this logic is considered “state lace”, which means it takes input and returns out. The documents mention the date of the date, but it may include anything like currency calculations or string verification.
In modern web applications, there are often pieces of logic that need to be managed over time. Within a common component, we have the ability to adopt the application in terms of the “state” of various variables within the ingredient. Sometimes they are reuse logic, or at least pieces of this logic, throughout the app.
For example, in the e -commerce application, you may have the logic to increase and reduce the amount of a product that someone is adding to his cart. This logic can be used on the product page and inside the automatic.
The appearance of these two places will be different, so reusing a complete component will not make sense-but we still want to maintain the code so that the code can be maintained. This is the place where composers come.
(It is worth noting that not everything needs to be composed. The logic that is used in only one component should not be made in the composable until one is necessary.)
Easy Compositable Examples
Let’s take a look at a simple counter example. Here is some code for a very easy Counter
Ingredient
class="bg-teal-100 border-2 border-gray-800 rounded-xl p-4 w-64">
class="text-center mb-4">
class="text-lg font-medium text-gray-800">Count: {{ count }}
class="flex gap-2 justify-center">
The production of this component will look like this:
It does a great job, but if we remove the need for the same counter logic in another component with a completely different shape and feeling, we will repeat the logic. We can remove the logic into a composingable and access the same state logic wherever we need.
import { ref } from 'vue'
import type { Ref } from 'vue'
export default function useCounter(): Readonly<{
count: Ref<number>
increment: () => void
decrement: () => void
}> {
const count: Ref<number> = ref(0)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
return { count, increment, decrement }
}
Then we update the script tag in the component to use the composables:
...
We can now use this logic in a number of ingredients in the app.
You’ll see that only logic has been copied and each component still has its own copy count
The use of state composables does not mean that the state is shared in components, only the logic of the state.
Complicated composables
In Vue Documents, they give an example of using a compose to recover ASYnc data. I have two problems with the example I have given. Most importantly, real -world applications are not a mistake to deal with the error. It is understandable that they just want to use the composingables directly. But I wanted to show another realistic implementation.
For the Util Function fetch
Before you go to the composer, we need to set up a utilized function for this fetch
API. The reason for this is that we want to make sure that if every request fails, it throws a mistake. fetch
If the application responds as an error, API does not throw any mistake. We have to check response.ok
To confirm the status and then throw the mistake if necessary.
export async function handleFetch(url: string, options: RequestInit = {}): Promise<Response> {
const res = await fetch(url, options)
if (!res.ok) {
const err = await res.text()
throw new Error(err)
}
return res
}
UseasyNcstate Compositable
When working with ASYNC State, requests may be in a few different states:
Below
Solution
Rejection
In addition to these states, we want to track data or error that will be returned from the request.
import { shallowRef } from 'vue'
import type { Ref } from 'vue'
export type AsyncState = {
data: Refnull>
error: Ref<Error | null>
isPending: Ref<boolean>
isResolved: Ref<boolean>
isRejected: Ref<boolean>
}
export default function useAsyncState<T>(promise: Promise ): AsyncState<T> {
const data = shallowRefnull>(null)
const error = shallowRef<Error | null>(null)
const isPending = shallowRef(false)
const isResolved = shallowRef(false)
const isRejected = shallowRef(false)
data.value = null
error.value = null
isPending.value = true
isRejected.value = false
isResolved.value = false
promise.then((result) => {
data.value = result
isPending.value = false
isResolved.value = true
}).catch(err => {
error.value = err
isPending.value = false
isRejected.value = true
})
return { data, error, isPending, isResolved, isRejected }
}
It has some other clear qualities for different states rather than relying on values data
And error
. You will also see that this compose is promised instead of a URL wire like the DOCS Show. There will be different types of reactions in different perspectives and I wanted to be able to handle those out of this composing.
Used in a component
I have set a closing point that will wait successfully or for a random number of seconds before responding successfully. My component is calling this closing point using the composable and using composable data to update the template.
With such a disturbed condition:
You can see a working example https://undonseding-composables.pages.dev/.
Explaining and understanding it to make it a bit easier l i, i’m breaking it tag and the
sections of the component.
Script
Here we have a way, getRandomResponse
Which calls a closing point and returns the promise. Then this promise has been transferred to him useAsyncState
While handleMakeRequest
Called. Who puts the entire return in the cost randomResponseData
Reef, which we can then use inside the template.
Instead of displaying the full template, I’ll just show part of it.
Here you can see that two different buttons are used in terms of state. I am using a separate button element to indicate a “loading” condition, but in practice you can use composable properties to set disabled
Change the button property and text.
<button
v-if="
!randomResponseData?.isPending &&
!randomResponseData?.error &&
!randomResponseData?.data
"
class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
@click="handleMakeRequest"
>
Make Request
button>
<button
v-if="randomResponseData?.isPending"
disabled
class="px-6 py-3 bg-blue-600 text-white font-medium rounded-lg opacity-75 cursor-not-allowed flex items-center mx-auto"
>
<svg
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
xmlns="
fill="none"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
>circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
>path>
svg>
Loading...
button>
Here are some rows from the table:
<tr class="divide-x divide-gray-200">
<td class="py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0">
isPending
td>
<td
class="p-4 text-sm whitespace-nowrap text-gray-500"
:class="randomResponseData?.isPending ? 'bg-blue-500' : 'bg-gray-300'"
>td>
<td class="p-4 text-sm whitespace-nowrap text-gray-500">
{{ randomResponseData?.isPending }}
td>
tr>
<tr class="divide-x divide-gray-200">
<td class="py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0">
data
td>
<td
class="p-4 text-sm whitespace-nowrap text-gray-500"
:class="randomResponseData?.data ? 'bg-green-500' : 'bg-gray-300'"
>td>
<td class="p-4 text-sm whitespace-nowrap text-gray-500">
{{ unref(randomResponseData?.data)?.msg }}
td>
tr>
In them tr
Tags, you can see the template offering different things in terms of the state coming from the composing.
Looking more fully on the code L you, you can visit Gut Hub Rippo. You can also see how a combination of composables, Vivos, similar functionality handles:
In the next article, I will dive into their implementation.
Conclusion
Composeable Vue 3 has an incredibly useful tool. As the projects grow in size and scope, knowing how and when composables are to use can improve the care of the project for a long time.
The key is indicating that when you have a state logic that needs to be reused in the ingredients, then remove it in a well -made composingable that handles the edge matters properly.
More real examples of the world Lou You can check it out Vueuse Library And Repo.