# API de Composición

Esta sección utiliza la sintaxis de componentes de un solo archivo para ejemplos de código

# setup

Una opción de componente que se va a ejecutar antes de que se cree el componente, tan pronto son recuperados las props. Sirve como el punto de entrada para APIs de composición.

  • Argumentos:

    • {Data} props
    • {SetupContext} context

    Similar a this.$props cuando se utiliza la API de opciones, el objeto props solo contendrá props declaradas explícitamente. También, todas claves declaradas de props serán presentes en el objeto props, sin tener en cuenta de si fue pasada por el componente padre o no. Las props opcionales ausentes tendrán un valor de undefined.

    Si necesita comprobar la ausencia de una prop opcional, puede darle un Symbol como su valor por defecto:

    const isAbsent = Symbol()
    
    export default {
      props: {
        foo: { default: isAbsent }
      },
      setup(props) {
        if (props.foo === isAbsent) {
          // foo no fue proporcionado
        }
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  • Tipar:

    interface Data {
      [key: string]: unknown
    }
    
    interface SetupContext {
      attrs: Data
      slots: Slots
      emit: (event: string, ...args: unknown[]) => void
      expose: (exposed?: Record<string, any>) => void
    }
    
    function setup(props: Data, context: SetupContext): Data
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    TIP

    Para obtener inferencia de tipo para los argumentos pasados a setup(), el uso de defineComponent es necesario.

  • Ejemplo

    Con la plantilla:

    <!-- MyBook.vue -->
    <template>
      <div>{{ readersNumber }} {{ book.title }}</div>
    </template>
    
    <script>
      import { ref, reactive } from 'vue'
    
      export default {
        setup() {
          const readersNumber = ref(0)
          const book = reactive({ title: 'El guía de Vue 3' })
    
          // expone a la plantilla
          return {
            readersNumber,
            book
          }
        }
      }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    Con una función render:

    // MyBook.vue
    
    import { h, ref, reactive } from 'vue'
    
    export default {
      setup() {
        const readersNumber = ref(0)
        const book = reactive({ title: 'El guía de Vue 3' })
        // Por favor note que necesitamos explícitamente utilizar valor de ref aquí
        return () => h('div', [readersNumber.value, book.title])
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    Si retorna una función render, luego no puede retornar cualquieras otras propiedades. Si necesita exponer propiedades para que puedan ser accesadas externamente, p. ej, mediante una ref en el padre, puede utilizar expose:

    // MyBook.vue
    
    import { h } from 'vue'
    
    export default {
      setup(props, { expose }) {
        const reset = () => {
          // unas lógica de reestablecer (reset)
        }
    
        // La función expose puede ser llamada solo una vez. 
        // Si necesita exponer múltiples propiedades, todos de ellas deben ser 
        // incluidas en el objeto pasado a _expose_.
        expose({
          reset
        })
    
        return () => h('div')
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • Vea también: setup en la API de Composición

# Hooks de ciclo de vida

Los hooks de ciclo de vida pueden ser registrados con las funciones onX importadas directamente:

import { onMounted, onUpdated, onUnmounted } from 'vue'

const MyComponent = {
  setup() {
    onMounted(() => {
      console.log('mounted!')
    })
    onUpdated(() => {
      console.log('updated!')
    })
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Estas funciones de registración de ciclo de vida pueden ser utilizadas solo sincrónicamente durante setup(), debido a que dependen de estado global internal para ubicar la instancia activa actual (la instancia de componente cuya setup() está siendo llamada ahora mismo). Llamarlas sin una instancia activa actual resultará un error.

El contexto de la instancia del componente es también establecido durante la ejecución síncrona de los hooks de ciclo de vida. Como un resultado, los observadores y propiedades computadas creados sincrónicamente dentro de hooks de ciclo de vida son también automáticamente destruidos cuando el componente se desmonte.

  • Mapping entre las opciones de ciclo de vida de API de opciones y API de composición

    • beforeCreate -> utilice setup()
    • created -> utilice setup()
    • beforeMount -> onBeforeMount
    • mounted -> onMounted
    • beforeUpdate -> onBeforeUpdate
    • updated -> onUpdated
    • beforeUnmount -> onBeforeUnmount
    • unmounted -> onUnmounted
    • errorCaptured -> onErrorCaptured
    • renderTracked -> onRenderTracked
    • renderTriggered -> onRenderTriggered
    • activated -> onActivated
    • deactivated -> onDeactivated
  • Vea también: hooks de ciclo de vida de API de composición

# Provide / Inject

provide y inject habilitan inyección de dependencia. Ambos pueden solo ser llamado durante setup() con una instancia activa actual.

  • Tipar:

    interface InjectionKey<T> extends Symbol {}
    
    function provide<T>(key: InjectionKey<T> | string, value: T): void
    
    // sin un valor por defecto
    function inject<T>(key: InjectionKey<T> | string): T | undefined
    // con un valor por defecto
    function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
    // con una factoría
    function inject<T>(
      key: InjectionKey<T> | string,
      defaultValue: () => T,
      treatDefaultAsFactory: true
    ): T
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    Vue porporciona una interfaz InjectionKey que es un tipo genénico que extienda Symbol. Puede ser utilizada para sincronizar el tipo del valor inyectado entre el proveedor y el consumidor:

    import { InjectionKey, provide, inject } from 'vue'
    
    const key: InjectionKey<string> = Symbol()
    
    provide(key, 'foo') // provee valores que no son cadenas de caracteres resultará un error
    
    const foo = inject(key) // tipo de foo: string | undefined
    
    1
    2
    3
    4
    5
    6
    7

    Si se utiliza claves de cadena de caracteres o symbols sin tipo, el tipo del valor inyectado necesitará ser explícitamente declarado:

    const foo = inject<string>('foo') // string | undefined
    
    1
  • Vea también:

# getCurrentInstance

getCurrentInstance habilita acceso a una instancia internal de componente.

WARNING

getCurrentInstance solo es expuesto para casos de usuario avanzados, típicamente en librerías. El uso de getCurrentInstance es totalmente desaconsejado en el código de aplicación. NO lo utilice como una salida de emergencia para obtener el equivalente de this en API de composición.

import { getCurrentInstance } from 'vue'

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance()

    internalInstance.appContext.config.globalProperties // acceder a globalProperties
  }
}
1
2
3
4
5
6
7
8
9

getCurrentInstance solo funciona durante setup o hooks de ciclo de vida

Cuando se utiliza afuera de setup o hooks de ciclo de vida, por favor llame a getCurrentInstance() en setup y utilice la instancia en su lugar.

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance() // funciona

    const id = useComponentId() // funciona

    const handleClick = () => {
      getCurrentInstance() // no funciona
      useComponentId() // no funciona

      internalInstance // funciona
    }

    onMounted(() => {
      getCurrentInstance() // funciona
    })

    return () =>
      h(
        'button',
        {
          onClick: handleClick
        },
        `uid: ${id}`
      )
  }
}

// también funciona si está llamada en un _composable_
function useComponentId() {
  return getCurrentInstance().uid
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32