阿里云主机折上折
  • 微信号
Current Site:Index > The exposure method of component instances

The exposure method of component instances

Author:Chuan Chen 阅读数:54115人阅读 分类: Vue.js

In Vue 3, the component instance exposure mechanism is a core feature of the Composition API. Through APIs like expose and ref, developers can precisely control the properties and methods exposed by components to the outside world, while using template refs to directly access DOM or child component instances. This design offers both flexibility and encapsulation.

Basic Exposure Methods for Component Instances

By default, Vue 3 components expose the following:

  1. All properties in the object returned by setup()
  2. Options like data, computed, and methods in the component configuration.
// Child component Child.vue
export default {
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    return { count, increment }
  }
}

// Usage in parent component
<template>
  <Child ref="childRef" />
</template>

<script setup>
import { ref } from 'vue'
const childRef = ref(null)
// Can access childRef.value.count and childRef.value.increment
</script>

Controlling Exposed Content with expose

The expose function allows precise control over what is exposed:

// Child component
export default {
  setup(props, { expose }) {
    const count = ref(0)
    const increment = () => count.value++
    const reset = () => (count.value = 0)
    
    // Only expose the increment method
    expose({
      increment
    })
    
    return { count, increment, reset }
  }
}

// In parent component
childRef.value.increment() // Works
childRef.value.reset() // Error, not exposed
childRef.value.count // Error, not exposed

Template Refs and Component Instances

In the Composition API, template refs are implemented using ref:

<template>
  <Child ref="childRef" />
  <input ref="inputRef" />
</template>

<script setup>
import { ref, onMounted } from 'vue'

const childRef = ref(null)
const inputRef = ref(null)

onMounted(() => {
  console.log(childRef.value) // Child component instance
  console.log(inputRef.value) // DOM element
})
</script>

Component Type Inference and TypeScript

In TypeScript environments, you can declare types for component refs:

// Child component
const Child = defineComponent({
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    return { count, increment }
  }
})

// Parent component
<template>
  <Child ref="childRef" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
const childRef = ref<InstanceType<typeof Child> | null>(null)
// Now with type hints
childRef.value?.increment()
</script>

Handling Multiple Component Refs

When dealing with refs for multiple identical components:

<template>
  <Child v-for="i in 3" :key="i" :ref="setChildRef" />
</template>

<script setup>
import { ref } from 'vue'

const childRefs = ref([])
const setChildRef = el => {
  if (el) childRefs.value.push(el)
}
</script>

Dynamic Components and Instance Exposure

Dynamic components also support instance exposure:

<template>
  <component :is="currentComponent" ref="dynamicComponentRef" />
</template>

<script setup>
import { shallowRef } from 'vue'

const currentComponent = shallowRef(ComponentA)
const dynamicComponentRef = ref(null)
</script>

Instance Forwarding in Higher-Order Components

Forwarding child component instances in HOCs:

// HOC component
export default defineComponent({
  setup(_, { expose }) {
    const childRef = ref(null)
    
    expose({
      getChildInstance: () => childRef.value
    })
    
    return () => h(Child, { ref: childRef })
  }
})

Ref Handling in Render Functions

Manual ref handling in render functions:

export default {
  setup() {
    const root = ref(null)
    
    return () => 
      h('div', { ref: root }, [
        h(Child, { ref: 'child' })
      ])
  }
}

Component Instance Lifecycle

Accessibility of exposed instances during different lifecycle stages:

<template>
  <Child v-if="show" ref="childRef" />
</template>

<script setup>
import { ref, watch } from 'vue'

const show = ref(true)
const childRef = ref(null)

watch(show, (newVal) => {
  console.log(childRef.value) // Changes based on show's value
})
</script>

Asynchronous Calls to Component Methods

Handling instance access in asynchronous scenarios:

const childRef = ref(null)

const handleAsync = async () => {
  await nextTick()
  childRef.value?.someMethod()
}

Debugging Techniques for Component Instances

Tips for inspecting instance content during development:

onMounted(() => {
  // Inspect component instance in console
  console.log(childRef.value)
  
  // Temporarily expose all content (not recommended for production)
  childRef.value.$el.__vue__ // Access internal instance
})

Comparison with Vue 2

Instance access in Vue 2:

// Vue 2 Options API
this.$refs.childRef.methodName()

Changes in Vue 3:

  1. Explicit ref declaration required
  2. Controlled exposure via expose
  3. Better TypeScript support

Performance Considerations

Potential performance issues from frequent instance access:

// Avoid frequent access in render functions
const BadExample = {
  setup() {
    const childRef = ref(null)
    return () => {
      // Executes on every render
      if (childRef.value) {
        childRef.value.update()
      }
      return h(Child, { ref: childRef })
    }
  }
}

Edge Case Handling

Handling potentially null instance refs:

// Safe access
const value = childRef.value?.someProp ?? defaultValue

// Protected method call
childRef.value?.someMethod?.()

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.