根上下文

用 defineRootContext 和 useRootContext 共享和使用根状态

根上下文用于在 App.vue 中定义应用级状态,并提供给页面、组件或应用内其他文件使用。它适合承载应用骨架相关状态,而不是替代所有业务状态管理。

能力定位

根上下文解决的是跨页面读取应用根状态的问题。

典型场景:

  • 主题状态。
  • 应用外壳方法。
  • 应用共享弹窗。
  • 应用级共享的状态。

defineRootContext

App.vue 中无需导入,可以直接使用 defineRootContext() 定义并返回共享状态。

src/App.vue
<script setup>
const { title, count, increment, isDark } = defineRootContext(() => {
  const title = ref('Hello Oiyo')
  const count = ref(0)

  function increment() {
    count.value += 6
  }

  const isDark = useSystemDark()

  return { title, count, increment, isDark }
})
</script>

返回数据就是对外暴露的根上下文。这些状态可以在 App.vue 中使用,也可以被页面或其他应用文件读取。

用于定义共享状态的 defineRootContext 方法只允许在 App.vue 中使用。

useRootContext

通过 useRootContext 可以在 页面组件应用内任意文件 中无需导入,直接消费 defineRootContext() 定义的共享状态。

应用骨架使用

这里的应用骨架指 App.vue<template> 部分。

App.vue 内,可以直接解构 defineRootContext() 返回的状态。

src/App.vue
<script setup>
const { increment } = defineRootContext(() => {
  const count = ref(0)

  function increment() {
    count.value += 1
  }

  return { increment }
})
</script>

<template>
  <view @click="increment">
    触发根部叠加
  </view>
</template>
应用骨架模板中使用的变量和方法都应通过 defineRootContext() 暴露。

页面中使用

页面使用 useRootContext() 读取根上下文。

src/pages/home/index.vue
<script setup lang="ts">
const { title, increment } = useRootContext<{
  title: Ref<string>
  increment: () => void
}>()

onLoad(() => {
  console.log('生命周期中使用', title.value)
})
</script>

<template>
  <view>{{ title }}</view>

  <view @click="increment">
    模板中触发方法
  </view>
</template>

应用文件中使用

store、composable 等应用内文件可以读取根上下文。

export const useAppStore = defineStore('oiyo-app', () => {
  const { title } = useRootContext<{ title: Ref<string> }>()

  const hey = computed(() => `你好 - ${title.value}`)

  return { hey }
})

类型标注

defineRootContext()useRootContext() 都支持显式标注共享状态的类型。

useRootContext() 建议显式标注当前文件需要的字段。

读取少量字段:

const { title } = useRootContext<{ title: Ref<string> }>()

读取多个字段:

interface RootContext {
  title: Ref<string>
  increment: () => void
}

const { title, increment } = useRootContext<RootContext>()

验证可用

检查:

  1. defineRootContext() 是否定义在 App.vue
  2. return 中是否包含所需共享的状态。
  3. 页面局部状态是否没有误放进根上下文。