2026.01.28

组件实例 -> getCurrentInstance 的实现

在开发过程中,有时我们需要访问组件实例本身,比如获取组件的属性、上下文或者其他内部状态。Vue 提供了 getCurrentInstance API,允许我们在 setup 函数或生命周期钩子中获取当前组件的实例。

在开发过程中,有时我们需要访问组件实例本身,比如获取组件的属性、上下文或者其他内部状态。Vue 提供了 getCurrentInstance API,允许我们在 setup 函数或生命周期钩子中获取当前组件的实例。

问题场景

让我们先通过一个示例来观察 getCurrentInstance 的使用场景:

<div id="app"></div>

<script type="module">
  import { h, createApp, getCurrentInstance } from '../dist/vue.esm.js'

  const Comp = {
    setup() {
      // 获取当前组件实例
      const instance = getCurrentInstance()
      console.log('🚀 ~ instance:', instance)

      return () => {
        return h('div', [
          h('p', 'p'),
        ])
      }
    }
  }

  createApp(Comp).mount('#app')
</script>

核心问题:

  • getCurrentInstance 只能在 setup 或生命周期钩子中使用
  • 需要在正确的时机设置和清除当前组件实例
  • 类似于 effectactiveSub 机制,需要一个全局变量来追踪当前实例

实现 getCurrentInstance

1. 基础架构设计

参考 effectactiveSub 的实现思路,我们只需要在 setup 执行前设置当前组件实例,执行完成后清除即可:

/**
 * 全局变量,用于追踪当前正在执行的组件实例
 * 类似于 effect 中的 activeSub
 */
let currentInstance = null

/**
 * 获取当前组件实例
 * 只能在 setup 或生命周期钩子中使用
 */
export function getCurrentInstance() {
  return currentInstance
}

/**
 * 设置当前组件实例
 * 在 setup 执行前调用
 */
function setCurrentInstance(instance) {
  currentInstance = instance
}

/**
 * 清除当前组件实例
 * 在 setup 执行完成后调用
 */
function unsetCurrentInstance() {
  currentInstance = null
}

2. 在 setup 流程中集成

接下来,我们需要在 setupStateFulComponent 函数中集成实例的管理逻辑:

/**
 * 设置有状态组件
 */
function setupStateFulComponent(instance) {
  const { type } = instance

  instance.proxy = new Proxy(instance.ctx, publicInstanceProxyHandlers)

  if (isFunction(type.setup)) {
    const setupContext = createSetupContext(instance)
    instance.setupContext = setupContext

    // 设置当前组件的实例
    setCurrentInstance(instance)

    // 执行 setup 函数
    const setupResult = type.setup(instance.props, setupContext)

    // 清除当前组件的实例
    unsetCurrentInstance()

    handleSetupResult(instance, setupResult)
  }

  if (!instance.render) {
    instance.render = type.render
  }
}

执行流程:

  1. 创建 setupContext,包含 attrsemitslotsexpose 等上下文信息
  2. 调用 setCurrentInstance(instance) 设置当前实例
  3. 执行 type.setup(),此时在 setup 内部可以调用 getCurrentInstance() 获取实例
  4. 调用 unsetCurrentInstance() 清除当前实例,确保后续不会被误用
  5. 处理 setup 的返回结果

总结

至此,我们完成了 getCurrentInstance 的实现:

1. 核心机制

  • 使用全局变量 currentInstance 追踪当前组件实例
  • 类似 effectactiveSub 模式,确保正确的作用域

2. API 设计

  • getCurrentInstance():获取当前组件实例
  • setCurrentInstance():在 setup 执行前设置实例
  • unsetCurrentInstance():在 setup 执行完成后清除实例

3. 使用限制

  • 只能在 setup 函数或生命周期钩子中使用
  • setup 外部调用会返回 null

4. 工作流程

  1. setupStateFulComponent 被调用时
  2. 创建 setupContext 后,设置 currentInstance
  3. 执行 setup 函数,内部可通过 getCurrentInstance() 访问实例
  4. setup 执行完成后,清除 currentInstance

这个实现确保了组件实例在正确的作用域内可访问