# Vue 3 `<script setup>` 中变量声明的正确姿势:何时必须使用 `ref()`?

在使用 Vue 3 的 <script setup> 语法糖进行开发时,很多开发者会遇到一个常见问题:

"为什么我直接修改变量会报错?明明在模板里能用啊!"

本文将彻底讲清楚这个核心规则,并提供最佳实践建议。


🔥 核心规则

在 Vue 3 的 <script setup> 中:

所有需要被修改的变量都必须使用 ref() 包装!

无论该变量是否在模板中使用。


❓ 为什么会这样?

<script setup> 内部会对顶层绑定的变量进行只读处理 (类似 Object.freeze()),这是 Vue 3 的有意设计,目的包括:

  1. 防止意外修改:避免直接赋值导致响应式系统失效
  2. 性能优化:只读变量可被编译器更好地优化
  3. 明确意图 :通过 ref() 显式声明"这是一个可变的响应式数据"

🚫 错误示例 vs ✅ 正确写法

❌ 错误:直接声明并修改普通变量

javascript 复制代码
// 报错!TypeError: "xxx" is read-only
const noMoreData = false;
noMoreData = true;  // ❌ 运行时错误!

✅ 正确:使用 ref() 包装

javascript 复制代码
import { ref } from 'vue';

const noMoreData = ref(false);
noMoreData.value = true;  // ✅ 完全正常

💡 注意:修改时要通过 .value,但在模板中使用时无需 .value(Vue 自动解包)


📋 实际开发中的使用指南

变量类型 是否需要 ref() 示例
模板中使用的数据 ✅ 必须 const list = ref([])
需要动态修改的状态 ✅ 必须 const loading = ref(false)
分页/加载控制标志 ✅ 必须 const noMoreData = ref(false)
常量(永不修改) ❌ 不需要 const PAGE_SIZE = 20
配置项/URL 基础路径 ❌ 不需要 const BASE_URL = 'https://api.example.com'
工具函数 ❌ 不需要 const formatDate = (date) => {...}

✅ 推荐代码结构

javascript 复制代码
<script setup>
import { ref, computed } from 'vue'

// ✅ 需要 ref() 的变量(会变化 or 模板使用)
const userList = ref([])
const isLoading = ref(false)
const currentPage = ref(1)
const hasMore = ref(true)

// ❌ 不需要 ref() 的变量(常量/函数)
const PAGE_SIZE = 10
const API_BASE = '/api'
const formatTime = (timestamp) => {
  return new Date(timestamp).toLocaleString()
}

// 计算属性(自动响应式,无需 ref)
const totalUsers = computed(() => userList.value.length)
</script>

⚠️ 常见误区提醒

  • 误区1 :"只要不在模板里用,就可以不用 ref"

    → 错!只要需要修改,就必须用 ref

  • 误区2 :"用 let 声明就能修改"

    → 错!<script setup> 中的 let 变量同样会被冻结

  • 误区3 :"可以用 reactive 代替 ref"

    → 对于基础类型(boolean/number/string),reactive 无效,必须用 ref


✅ 总结

在 Vue 3 <script setup> 中,请牢记:

  • 要修改?→ 用 ref()
  • 不修改?→ 普通变量即可

这不仅是语法要求,更是 Vue 3 响应式系统的设计哲学------让可变性显式化,让代码更安全、更清晰!

遵循这一原则,你将避免绝大多数"只读错误",写出更健壮的 Vue 3 应用!🚀

相关推荐
Csvn4 小时前
🧩「找不到模块」排查全记录——Monorepo 下 TypeScript 路径别名的 5 种「不通」与根治方案
前端
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
CodexDave4 小时前
MySQL事务隔离级别与MVCC机制解析
前端·数据库·mysql·nginx·性能优化·负载均衡
Ai_easygo5 小时前
AI Agent开发入门——从ReAct到Tool Calling,拆解Agent的底层运行逻辑
前端·人工智能·react.js
研☆香5 小时前
分析制作html页面,如何划分页面结构
前端
腻害兔6 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
kyriewen6 小时前
我扒了最近的前端面经——2026年面试不背八股文了,考这5样
前端·面试·ai编程
IT_陈寒6 小时前
Redis的持久化配置把我坑惨了:你以为数据安全了?
前端·人工智能·后端
小徐_23336 小时前
uni-app 项目别再从零搭了!3 个 Wot UI 起手模板怎么选?
前端·uni-app
张元清7 小时前
React useResizeObserver Hook:追踪元素尺寸变化(2026)
javascript·react.js