前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Vue 组合式函数模块状态与实例状态共享范围
VuVue应用与性能

Vue 组合式函数的 ref 放在模块顶层和函数内部,共享范围有什么区别?

状态的创建位置决定常见共享范围,函数叫 use 什么并不会自动替你隔离数据。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Vue#应用与性能#性能优化#测试
先看核心答案读代码示例
理解线索

三种常见状态寿命

  1. 调用范围一次组合式函数调用创建自己的容器
  2. 应用范围由一个应用实例拥有并向需要者提供
  3. 模块范围由同一加载模块的多个调用者共同访问

模块是否复用还受运行环境和加载方式影响,不能把模块单例简单等同于永远全局唯一。

核心回答

先记住这个答案

ref 在组合式函数内部创建时,每次调用通常获得独立状态;放在模块顶层时,同一模块实例的调用者会拿到同一个引用。前者适合局部编辑、分页等互不干扰的功能,后者适合经过明确设计的共享状态。但模块范围不一定等于单个用户或单个应用,尤其 SSR 中模块可能被多个请求复用,用户数据不能随意放入共享单例。需要应用或请求级状态时,应在相应工厂中创建并通过依赖注入或参数传递。

  • 函数内创建通常按调用隔离,模块顶层通常按模块实例共享
  • 共享数据与共享副作用的生命周期都要设计
  • SSR 应明确请求级隔离,不能依赖模块变量区分用户

用引用身份理解两种写法

两个列表各有自己的当前页,把 ref 放在函数内可以避免翻动一个列表影响另一个。若把它移到模块外,两次调用返回的可能正是同一页码引用,组件数量增加后才出现串联更新。重构时看起来只是移动一行,实际已经改变状态所有权。

下面把两种写法并列。共享函数返回同一个模块变量,本地函数每次调用重新创建 ref。比较两次调用的 count 身份,再只修改其中一次返回值,可以直接看到共享与隔离,而不必依赖组件渲染来猜测。

共享和隔离来自创建位置TypeScript
import { ref } from 'vue';

const sharedCount = ref(0);
function useSharedCounter() { return { count: sharedCount }; }

function useLocalCounter() {
  const count = ref(0);
  return { count };
}

两次 useSharedCounter 的 count 相同;两次 useLocalCounter 的 count 不同。该示例只演示状态范围,没有引入共享监听器或请求缓存。

共享状态还需要清楚的释放责任

共享一个连接状态时,多个组件可能都需要读取,但不能每个组件卸载时都无条件关闭同一连接。应由应用所有者、引用计数或其他明确策略管理资源寿命。共享 ref 本身很简单,真正复杂的是它背后的订阅、缓存与异步任务何时创建和停止。

本地状态也不保证完全独立。如果函数内创建的容器仍引用同一个外部对象,嵌套数据可能继续共享。判断范围要追踪所有可变来源,而不是只看最外层 ref 的声明位置;测试也应覆盖多个调用并存和其中一个销毁后的行为。

SSR 为什么要特别注意模块单例

服务端运行中,同一模块可能处理多个用户请求。把当前用户资料、权限相关输入或临时页面状态放在模块级 ref,可能让后来的请求读取前一个请求的数据。即使客户端页面之间共享符合预期,服务端的复用边界也不同。

常见做法是在应用或请求工厂中创建状态,再通过 provide/inject、显式参数或框架支持的状态管理交给需要者。测试应从干净状态开始,并模拟两个独立上下文验证隔离。简单清空全局变量难以处理并发请求,不应把它当作请求隔离的通用方案。

回答前,多想一步

容易答错的地方

每个组件调用 use 函数就一定独立
函数可能返回模块级引用,是否隔离取决于实际创建与引用关系。排查“Vue 组合式函数模块状态与实例状态共享范围”时还要核对输入、版本和执行顺序,并用反例确认修复后的边界。
SSR 里每个请求都会重新加载模块
运行环境可能复用模块及其变量,用户状态需要显式请求级设计。排查“Vue 组合式函数模块状态与实例状态共享范围”时还要核对输入、版本和执行顺序,并用反例确认修复后的边界。
试着用自己的话回答

面试官还会怎么问?

客户端全站共享状态可以放模块外吗?

简单场景可以,但要明确多应用、热更新、测试和资源清理的行为;复杂共享需求通常需要更清楚的所有者。

把模块 ref 每次初始化清零能避免请求污染吗?

并发请求可能互相覆盖,清零不是隔离。应为每个请求创建独立状态容器。针对“Vue 组合式函数模块状态与实例状态共享范围”,还应保留最小复现、预期结果和失败路径,避免只凭一次现象下结论。

如何测试一个 composable 是共享还是独立?

同时调用两次,比较引用并更新一侧,再检查另一侧变化;若有副作用,还要测试单侧释放不会破坏另一侧。

从一道题,走向一组知识

把知识连起来

应用与性能

Vue 组合式函数为什么用 use 命名,返回普通对象还是 reactive 对象?

返回 refs 并不会自动决定它们的共享范围

应用与性能

Vue 共享逻辑用组合式函数,跨层状态什么时候用 provide/inject?

通过应用或子树提供者安排状态归属

应用与性能

Vue 组合式函数怎样独立测试,什么时候仍需要挂载组件?

验证多调用隔离与清理行为继续对照“Vue 组合式函数模块状态与实例状态共享范围”的触发条件、结果与失败边界。

参考资料

  • Vue:组合式函数的实例状态
  • Vue:跨请求状态污染

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 用引用身份理解两种写法
  3. 共享状态还需要清楚的释放责任
  4. SSR 为什么要特别注意模块单例
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑