Uso de la función setup en Vue 3: Conceptos y Ejemplos Prácticos

  1. Propósito de setup en Vue 3

La función setup se introdujo para facilitar el uso de la Composition API en Vue 3, permitiendo organizar la lógica del componente de manera más modular.

  1. Ventajas sobre la API de Opciones

La API de Opciones (data, computed, methods, watch) puede ser eficaz, pero en componentes grandes dificulta la lectura. Con setup, se puede extraer lógica en funciones reutilizables, ocultando detalles innecesarios.

  1. Posición en el Ciclo de Vida

setup se ejecuta antes de created y beforeCreated, reemplazándolos. No se puede acceder a this dentro de setup. En su lugar, se usan ganchos del ciclo de vida como:

onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered
  1. Parámetros de setup

Acepta props y context. props es reactivo y no debe desestructurarse directamente; se usa toRefs. context no es reactivo y puede desestructurarse. Debe retornar un objeto.

props: ['valor']
setup(props, contexto) {
  // const {valor} = props // Incorrecto
  const {valor} = toRefs(props) // Correcto
  const {attrs, slots, emit} = contexto // Correcto
  return { valor }
}
  1. Jerarquía de Prioridades

Si data, props y setup definen la misma propiedad, la de setup tiene mayor prioridad. Ejemplo:

// Componente padre
setup() {
  const dato = ref('dato del padre')
  return { dato }
}

// Componente hijo
<template>
  <div>
    <h1>{{ dato }}</h1>
  </div>
</template>
<script>
import { toRefs } from 'vue'
export default {
  props: ['dato'],
  data() {
    return { dato: 'dato del hijo (data)' }
  },
  setup(props) {
    let dato = toRefs(props)
    dato = 'dato del hijo (setup)'
    return { dato }
  }
}
</script>

El resultado mostrará "dato del hijo (setup)".

  1. Importación de Funciones

Para usar ref, toRefs, computed, watch, etc., en setup, se deben importar explícitamente de Vue:

import { toRefs, ref, onMounted, nextTick } from 'vue'
  1. Aceso a Refs de Componentes Hijo

Para acceder a un componente hijo, se usa ref. Ejemplo con un formulario:

// Plantilla
<a-form ref="miFormulario" :model="datosFormulario" :rules="reglas">
  <a-form-item label="Nombre">
    <a-input v-model:value="datosFormulario.nombre" />
  </a-form-item>
  <button @click="enviarFormulario">Enviar</button>
</a-form>

// En setup
setup() {
  const miFormulario = ref(null) // Ref para el componente
  const datosFormulario = reactive({ nombre: '' })
  const reglas = { nombre: [{ required: true, message: 'Requerido' }] }

  const enviarFormulario = () => {
    miFormulario.value.validate()
      .then(() => console.log('Éxito'))
      .catch(error => console.log('Error', error))
  }

  const reiniciarFormulario = () => {
    miFormulario.value.resetFields()
  }

  return { miFormulario, datosFormulario, reglas, enviarFormulario, reiniciarFormulario }
}
  1. Problema con Formularios en Versiones Específicas

En ant-design-vue ^2.0.0-rc.8 con Vue ^3.0.0, el evento submit puede fallar en la validación. Solución: usar un botón con método en lugar del evento submit del formulario.

// Evitar
<a-form @submit='enviarFormulario'>...</a-form>

// Mejor usar
<button @click="enviarFormulario">Enviar</button>
  1. Conflictos de Versiones

Hasta enero de 2021, Vite ^1.0.0-rc.1 y ant-design-vue ^2.0.0-rc.8 tenían incompatibilidades; se recomienda usar Vue CLI.

  1. Invocar Métodos de Componentes Hijo

Pasos: el hijo expone métodos en setup; el padre asigna un ref al hijo; en setup del padre, se accede al hijo via ref.

// Componente hijo
<template>
  <div>{{ valorRef }}</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
  setup() {
    const valorRef = ref('')
    const aceptarValor = (nuevoValor) => { valorRef.value = nuevoValor }
    return { aceptarValor, valorRef }
  }
})
</script>

// Componente padre
<template>
  <button @click="enviarDato">Enviar</button>
  <Hijo ref="hijoRef" />
</template>
<script>
import { defineComponent, ref } from 'vue'
import Hijo from './Hijo.vue'
export default defineComponent({
  components: { Hijo },
  setup() {
    const hijoRef = ref()
    const enviarDato = () => {
      hijoRef.value.aceptarValor('nuevo valor')
    }
    return { hijoRef, enviarDato }
  }
})
</script>
  1. Uso de defineComponent

defineComponent ayuda con la inferencia de tipos en TypeScript. Puede recibir props, setup, etc. Si solo se pasa setup, no se accede a props.

// Método 1: con props
export default defineComponent({
  props: ['param'],
  setup(props) {
    const valor = ref(props.param)
    return { valor }
  }
})

// Método 2: solo setup (sin acceso a props)
export default defineComponent((props, context) => {
  // props no disponible aquí
})
  1. Uso de watch para Observación Múltiple y Profunda

watch permite observar múltiples fuentes con arrays. Ejemplo:

import { ref, reactive, watch } from 'vue'

const miRef = ref('inicial')
const datos = reactive({
  formulario: {
    campo: 'valor'
  }
})

const desuscribir = watch(
  [miRef, () => datos.formulario.campo],
  ([nuevoRef, nuevoCampo], [viejoRef, viejoCampo]) => {
    console.log('Cambios:', nuevoRef, nuevoCampo)
  },
  { deep: true }
)

// Para detener la observación
setTimeout(() => desuscribir(), 5000)
  1. Uso de watchEffect

watchEffect ejecuta automáticamente una función reactivamente, sin proporcionar valores antiguos/nuevos. Ejemplo:

import { ref, watchEffect } from 'vue'

const contador = ref(0)
const detener = watchEffect(() => {
  console.log('Contador actual:', contador.value)
})

// Detener después de un tiempo
setTimeout(() => detener(), 10000)

// Incrementar contador
setInterval(() => contador.value++, 1000)

El parámetro flush controla el momento de ejecución: 'pre' (antes de actualización), 'post' (después), 'sync' (sincrónico).

  1. Acceso a Router y Route

Para usar el router y la ruta en setup, se importan de vue-router:

import { useRoute, useRouter } from 'vue-router'

setup() {
  const ruta = useRoute()
  const enrutador = useRouter()
  // Uso de ruta.query, enrutador.push(), etc.
}

Etiquetas: Vue 3 Composition API setup ref toRefs

Publicado el 6-1 14:07