Crear Composable useFormTask.ts
Después de haber visto las dos secciones anteriores ya deberíamos de estar un poco familiarizado con los composables.
Ya creamos un composable que no recibe argumentos y otro que recibe las props
como primer argumento. No obstante, aún nos falta un escenario donde tengamos que pasar también el contexto o parte de él.
Creando el archivo ./composables/useFormTask.ts
Nota
No se preocupe si aún no se encuentra muy familiarizado con TypeScript, porque gracias a los complementos de vscode (Vue Language Features "Volar" y TypeScript Vue Plugin "Volar") estos nos ayuda con el soporte.
Tenga en cuenta que aquí estaremos pasando tanto las propiedades como el contexto. En este caso, los eventos ctx.emit
.
📃./composables/useFormTask.ts
import { ref } from 'vue'
import type { Task } from '@/types'
type Props = {
readonly task?: Record<string, any>;
readonly onSubmit?: ((...args: any[]) => any);
}
type Ctx = {
emit: (event: "submit", ...args: any[]) => void;
}
export default (props: Props, ctx: Ctx) => {
const form = ref(props.task as Task)
const submit = () => ctx.emit('submit', form.value )
return {
form,
submit
}
}
Gracias a TypeScript, este tipado sirve tanto para el verificado de tipos como para tener alguna documentación referente a lo que recibe la función.
Limpiando el archivo ./components/FormTask.vue
Solo nos queda importar el composable useFormTask
e instanciarlo para poder implementar sus propiedades y funciones de retorno.
Tenga en cuenta que las props
y el ctx
deben ser pasadas respectivamente como argumento a la función setup()
, ya que las necesitamos para pasarlas al composable useFormTask
.
📃./components/FormTask.vue
<script lang="ts">
import { defineComponent } from 'vue'
import useFormTask from '../composables/useFormTask'
export default defineComponent({
props: {
task: Object
},
emits: ['submit'],
setup(props, ctx) {
const {
form,
submit
} = useFormTask(props, ctx)
return {
form,
submit
}
}
})
</script>
<template>
<form @submit.prevent="submit">
<div class="m-2">
<label>Title</label>
<input type="text" v-model="form.title">
</div>
<div class="m-4">
<label>Description</label>
<textarea v-model="form.description"></textarea>
</div>
<div class="m-4">
<label>Done</label>
<input type="checkbox" v-model="form.done"/>
</div>
<button type="submit" class="btn btn-primary m-2">
Save
</button>
</form>
</template>
De esta forma todo queda mucho más limpio, reutilizable y testeable.