shallowRef适合大数据导出场景,因其仅对.value做响应式代理而不深度递归,避免内存浪费与性能卡顿;数据只读、整批替换、无需监听嵌套变化,配合toRaw可安全对接导出库。

在 Vue 3 中处理大数据导出(比如万级记录的 Excel 导出、CSV 下载或后台 API 批量提交)时,用 ref 存储原始数据集合会触发深度响应式代理——每条记录、每个字段都被 Proxy 包裹,不仅浪费内存,还可能让导出逻辑变慢、甚至因频繁触发依赖更新而卡顿。这时 shallowRef 是更轻量、更安全的选择。
为什么导出场景适合 shallowRef
导出数据通常具备以下特征:
- 数据是只读的,导出过程中不修改单个字段(如
list[0].status = 'exported') - 整个数据集往往是一次性生成、一次性使用(如
fetchExportData().then(data => exportList.value = data)) - 不需要监听内部任意嵌套属性的变化,只关心“整批是否换了”
- 数据可能来自
toRaw脱敏后的原始数组,或后端直返的 JSON,本身就不该被响应式污染
正确声明与赋值方式
直接用 shallowRef 初始化空数组或初始数据,后续整体替换即可:
import { shallowRef } from 'vue'const exportList = shallowRef([])// 或带初始值const exportList = shallowRef([{ id: 1, name: '张三' }, { id: 2, name: '李四' }])
获取数据后整体赋值,视图和导出逻辑立刻感知变化:
async function loadAndExport() { const data = await api.fetchBigList({ page: 1, pageSize: 10000 }) exportList.value = data // ✅ 触发响应,但无递归代理开销 triggerExport(exportList.value) // 传原始数组给导出工具(如 SheetJS)}
配合 toRaw 和导出工具使用
多数导出库(如 xlsx、csv-writer、FileSaver)只接受普通数组/对象,不兼容 Proxy。即使你用了 shallowRef,取值时也推荐显式转为原始数据再传入:
function triggerExport(rawData) { // rawData 已是普通数组(shallowRef.value 不是 Proxy) // 但为保险起见,尤其当数据来自 reactive 链路,可加 toRaw const safeData = Array.isArray(rawData) ? toRaw(rawData) : rawData XLSX.write(workbook, { type: 'array', bookType: 'xlsx' })}
注意:如果 exportList.value 本身就是从 toRaw(someReactiveList) 得来,那它已是纯数组,无需再套一层 toRaw;shallowRef 本身不增加代理层,只是让 .value 的赋值可响应。
避免常见误操作
- ❌ 不要对
exportList.value内部做响应式修改(如exportList.value.push(item)),这不会触发更新,且破坏导出一致性 - ❌ 不要用
ref包裹大数据,初始化瞬间可能阻塞主线程 - ✅ 如需局部更新(例如标记某几行“已导出”),先改原始数组,再调用
triggerRef(exportList)主动刷新 - ✅ 导出完成可清空:
exportList.value = [],轻量无负担
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











