createGlobalState源码解析及使用指南

一、什么是 createGlobalState?

createGlobalState 是 VueUse 中用于创建全局响应式状态的工具函数,它解决了 Vue 3 组合式 API 在跨组件状态共享时的上下文隔离问题。该函数允许我们在多个组件实例中共享同一个响应式状态,同时保持对 SSR 的友好支持。

二、源码核心解析(基于 vueuse v9.0.0)

1. 函数签名

typescript 复制代码
export function createGlobalState<T>(stateFactory: () => T): () => T

2. 核心实现逻辑

typescript 复制代码
import { getCurrentInstance, effectScope } from 'vue'

export function createGlobalState<T>(stateFactory: () => T) {
  let state: T
  const scope = effectScope(true)

  return () => {
    // 服务端渲染处理
    if (__SSR__ && getCurrentInstance()) {
      const ssrContext = useSSRContext()
      if (!ssrContext.__vueuse_global_states__) ssrContext.__vueuse_global_states__ = {}
      if (!(ssrContext.__vueuse_global_states__ as any)[stateId])
        (ssrContext.__vueuse_global_states__ as any)[stateId] = stateFactory()
      return (ssrContext.__vueuse_global_states__ as any)[stateId]
    }

    // 客户端逻辑
    if (!state) {
      state = scope.run(stateFactory)!
    }

    return state
  }
}

3. 关键技术点

  1. 单例模式实现
  • 通过闭包变量 state 保存状态实例
  • 使用 effectScope 管理响应式依赖
  • 首次调用时通过 scope.run() 初始化状态
  1. SSR 支持
  • 使用 __SSR__ 常量判断运行环境
  • 通过 useSSRContext() 获取 SSR 上下文
  • 将状态挂载到请求级别的上下文对象
  1. 生命周期管理
  • 自动绑定到当前组件实例
  • 组件卸载时自动停止 effectScope
  • 避免内存泄漏

三、使用示例

基础计数器示例

typescript 复制代码
// stores/useCounter.ts
import { createGlobalState, useStorage } from '@vueuse/core'

export const useCounter = createGlobalState(() => {
  const count = useStorage('global-counter', 0)
  const increment = () => count.value++
  return { count, increment }
})

// ComponentA.vue
<script setup>
const { count, increment } = useCounter()
</script>

// ComponentB.vue
<script setup>
const { count } = useCounter() // 共享同一状态
</script>

带自动清理的复杂状态

typescript 复制代码
const useGlobalTimer = createGlobalState(() => {
  const interval = ref<NodeJS.Timeout>()
  const seconds = ref(0)

  const start = () => {
    interval.value = setInterval(() => seconds.value++, 1000)
  }

  const stop = () => {
    clearInterval(interval.value)
    interval.value = undefined
  }

  onScopeDispose(stop) // 自动清理定时器

  return { seconds, start, stop }
})

四、注意事项

  1. 状态初始化时机
  • 状态在首次调用时初始化
  • 避免在服务端渲染时产生副作用
  1. 类型安全
  • 推荐使用 TypeScript 类型标注
  • 通过工厂函数确保类型一致性
  1. 内存管理
  • 复杂状态需手动清理资源
  • 使用 onScopeDispose 注册清理回调
  1. SSR 兼容
  • 状态键需保证唯一性
  • 避免在服务端存储敏感数据

五、实现原理图解

css 复制代码
[Component A] --> 调用工厂函数 --> [Global State]
       ↑                         ↗
       |                       /
[Component B] --------------→

六、与 Pinia 的对比

特性 createGlobalState Pinia
学习成本
类型支持 基础 完善
SSR 支持 内置 需要配置
开发工具支持 Vue DevTools
适合场景 简单全局状态 复杂应用状态

七、总结

createGlobalState 通过巧妙的闭包和 effectScope 使用,提供了轻量级的全局状态管理方案。它特别适合以下场景:

  • 需要快速共享简单状态的组件
  • 无需持久化状态的临时共享数据
  • 需要兼容 SSR 的全局状态管理
  • 不想引入额外状态管理库的小型项目

对于复杂应用场景,建议结合 Pinia 等专业状态管理库使用。理解其实现原理有助于我们更好地使用和调试全局状态相关的功能。

相关推荐
雪隐4 小时前
个人电脑玩AI-16让5060 Ti给你打工——MiniMax H3 提速实录:从"泡杯茶等视频"到"视频等你",一张 5060 Ti 的自我修养
前端·人工智能·后端
FungLeo5 小时前
Flutter Web 中文字体困境与渲染器选择:CanvasKit vs HTML renderer 实战
前端·flutter·html
敲代码的玉米C5 小时前
我修的那个 bug,制造了另一个 bug
前端·人工智能·架构
gis开发之家5 小时前
《Vue3 从入门到大神50篇》Vue3 源码详解(二十):生命周期钩子源码解析 —— onMounted / onUpdated 如何实现?
前端·javascript·前端框架·vue3·vue3源码
Narrastory5 小时前
我用 Claude Code 写代码不到 2 小时,却花了 3 天做完这个软件—Vibe Coding 的正确姿势,是设计不是生成
前端·人工智能·github
Enaium5 小时前
我实现了KMP的SDL绑定并编写了高性能软光追
前端·kotlin
古夕5 小时前
本地正常线上白屏:一次路由切换后刷新恢复问题的排查与修复
前端·ai编程
栀鸢ouo6 小时前
解决Element Plus表格展开行横向溢出、滚动截断问题(项目实战方案)
前端·vue.js
用户39051332192886 小时前
写了5年JS,才发现这10个方法能少写一半代码
前端
平凡的阿泽6 小时前
我用TRAE Work手搓了一个「谁是卧底」小游戏
前端·javascript