Vue3響應(yīng)式數(shù)據(jù)轉(zhuǎn)回原始普通對(duì)象的方法詳解
在 Vue(尤其 Vue3)里,把響應(yīng)式數(shù)據(jù)(Proxy/Ref)轉(zhuǎn)回原始普通對(duì)象(用 toRaw),核心是:繞開(kāi)響應(yīng)式代理、避免不必要更新、兼容外部系統(tǒng)、提升性能、防止異常。
一、先搞懂:響應(yīng)式 vs 原始數(shù)據(jù)
- 響應(yīng)式數(shù)據(jù):
reactive/ref生成的 Proxy 代理對(duì)象,自帶 getter/setter 攔截,用于依賴收集與視圖自動(dòng)更新。 - 原始數(shù)據(jù):被代理前的普通對(duì)象/數(shù)組/值,無(wú) Proxy 包裹,修改不會(huì)觸發(fā) Vue 響應(yīng)式更新。
二、為什么要轉(zhuǎn)成原始數(shù)據(jù)(核心場(chǎng)景)
1. 與第三方庫(kù)/原生 API 兼容(最常見(jiàn))
很多庫(kù)/API 不認(rèn)識(shí) Vue 的 Proxy,直接傳會(huì)報(bào)錯(cuò)、序列化異?;蛐袨楫惓!?/p>
JSON 序列化/存儲(chǔ):JSON.stringify 對(duì) Proxy 可能輸出異常(含內(nèi)部元數(shù)據(jù)),必須轉(zhuǎn)原始
const user = reactive({ name: '張三' })
// ? 可能輸出帶 __v_isReactive 等內(nèi)部字段
localStorage.setItem('user', JSON.stringify(user))
// ? 正確:轉(zhuǎn)原始再序列化
localStorage.setItem('user', JSON.stringify(toRaw(user)))圖表/地圖/Three.js/D3 等外部庫(kù):它們期望純 JS 對(duì)象,傳 Proxy 會(huì)報(bào)錯(cuò)或性能極差
import * as d3 from 'd3'
const data = reactive([1,2,3])
d3.select('svg').selectAll('rect').data(toRaw(data)) // ? 必須原始
Lodash/工具函數(shù):深層遍歷/克隆時(shí),Proxy 會(huì)觸發(fā)額外依賴追蹤,導(dǎo)致性能問(wèn)題或死循環(huán)
2. 性能優(yōu)化:批量/大量數(shù)據(jù)操作
對(duì)超大數(shù)組/對(duì)象做循環(huán)、排序、過(guò)濾、批量修改時(shí):
- 直接操作響應(yīng)式對(duì)象:每一次修改都會(huì)觸發(fā)依賴收集與可能的更新,性能極低
- 轉(zhuǎn)原始后操作:無(wú) Proxy 開(kāi)銷、不觸發(fā)更新,最后再同步回響應(yīng)式對(duì)象
const list = reactive(Array(10000).fill(0)) const rawList = toRaw(list) // 批量處理:只操作原始,不觸發(fā)更新 for (let i = 0; i < rawList.length; i++) rawList[i] = i * 2 // 最后同步一次(可選) list.splice(0, list.length, ...rawList)
3. 避免無(wú)限遞歸/循環(huán)更新
場(chǎng)景1:對(duì)象自引用(如樹(shù)、鏈表、狀態(tài)里存自身)
const state = reactive({ data: null })
state.data = toRaw(state) // ? 存原始,避免 Proxy 遞歸監(jiān)聽(tīng)自己
場(chǎng)景2:監(jiān)聽(tīng)/計(jì)算屬性里修改自身,容易死循環(huán);用原始數(shù)據(jù)做中間計(jì)算
4. 只讀不觸發(fā)響應(yīng)式(調(diào)試/日志/臨時(shí)計(jì)算)
打印/調(diào)試時(shí),不想觸發(fā)依賴追蹤,也不想看到 Proxy(Object),想看真實(shí)數(shù)據(jù)
const form = reactive({ name: '李四' })
console.log(toRaw(form)) // { name: '李四' },干凈的原始對(duì)象
臨時(shí)計(jì)算、判斷、緩存,不需要視圖更新,用原始更安全高效
5. 提交后端/接口請(qǐng)求
后端只認(rèn)普通 JSON,不認(rèn) Proxy;雖然多數(shù) axios/fetch 能自動(dòng)處理,但轉(zhuǎn)原始更穩(wěn)妥、避免隱式問(wèn)題
const params = reactive({ id: 1, name: 'xxx' })
axios.post('/api', toRaw(params)) // ? 更干凈
6. 規(guī)避響應(yīng)式副作用
- 某些場(chǎng)景下,你明確不希望修改觸發(fā)視圖更新(如臨時(shí)草稿、后臺(tái)計(jì)算),用原始數(shù)據(jù)操作
三、怎么轉(zhuǎn):Vue3 核心 API
import { reactive, ref, toRaw } from 'vue'
// 1. reactive 對(duì)象 → 原始
const user = reactive({ name: '張三' })
const rawUser = toRaw(user) // 普通對(duì)象
// 2. ref 對(duì)象 → 原始(先取 .value)
const count = ref(0)
const rawCount = toRaw(count.value) // 原始值
// 3. 只讀/淺響應(yīng) → 也能轉(zhuǎn)
const ro = readonly(user)
toRaw(ro) === rawUser // true
四、重要注意
toRaw只解最外層:嵌套對(duì)象如果也是響應(yīng)式,依然是 Proxy,需要遞歸處理- 修改原始會(huì)同步到響應(yīng)式:原始與響應(yīng)式指向同一塊內(nèi)存,改原始會(huì)改數(shù)據(jù),但不觸發(fā)更新
- 不要替換響應(yīng)式對(duì)象:
user = rawUser會(huì)丟失響應(yīng)式,應(yīng)修改屬性或用Object.assign - Vue2 不同:Vue2 用
Object.defineProperty,無(wú)toRaw,一般用JSON.parse(JSON.stringify(obj))深拷貝轉(zhuǎn)普通對(duì)象
五、一句話總結(jié)
需要轉(zhuǎn)原始數(shù)據(jù),本質(zhì)是:當(dāng)你要和 Vue 響應(yīng)式系統(tǒng)“脫鉤”時(shí)——和外部交互、大量計(jì)算、避免遞歸、只看不更、性能敏感,就用 toRaw 拿原始數(shù)據(jù)。
以上就是Vue3響應(yīng)式數(shù)據(jù)轉(zhuǎn)回原始普通對(duì)象的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue3響應(yīng)式數(shù)據(jù)轉(zhuǎn)回原始普通對(duì)象的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue自定義指令實(shí)現(xiàn)卡片翻轉(zhuǎn)功能
這篇文章主要給大家介紹了Vue自定義指令實(shí)現(xiàn)卡片翻轉(zhuǎn)功能的代碼示例,文章通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參幫助,需要的朋友可以參考下2023-11-11
Vue登錄頁(yè)面的動(dòng)態(tài)粒子背景插件實(shí)現(xiàn)
本文主要介紹了Vue登錄頁(yè)面的動(dòng)態(tài)粒子背景插件實(shí)現(xiàn),將登錄組件背景設(shè)置為 "粒子背景",具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
Vue 3 中使用路由參數(shù)跳轉(zhuǎn)時(shí) watch 觸發(fā)重復(fù)請(qǐng)求問(wèn)題解決
Vue3中watch(route.query.id)可能因跨頁(yè)參數(shù)變化重復(fù)觸發(fā)請(qǐng)求,需通過(guò)路由name判斷當(dāng)前頁(yè)面,避免誤操作,route.query是響應(yīng)式,setup不重執(zhí)行,watch需手動(dòng)處理上下文,本文給大家介紹Vue 3 中使用路由參數(shù)跳轉(zhuǎn)時(shí) watch 觸發(fā)重復(fù)請(qǐng)求問(wèn)題解決,感興趣的朋友一起看看吧2025-07-07
vue在mounted中window.onresize不生效問(wèn)題及解決
這篇文章主要介紹了vue中在mounted中window.onresize不生效問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
關(guān)于VUE的編譯作用域及slot作用域插槽問(wèn)題
這篇文章主要介紹了VUE 的編譯作用域及slot作用域插槽問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
基于 vue-skeleton-webpack-plugin 的骨架屏實(shí)戰(zhàn)
這篇文章主要介紹了基于 vue-skeleton-webpack-plugin 的骨架屏實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
vue3實(shí)現(xiàn)小程序手機(jī)號(hào)一鍵登錄功能
這篇文章主要為大家詳細(xì)介紹了如何使用vue3實(shí)現(xiàn)小程序手機(jī)號(hào)一鍵登錄功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12
基于better-scroll 實(shí)現(xiàn)歌詞聯(lián)動(dòng)功能的代碼
BetterScroll 是一款重點(diǎn)解決移動(dòng)端(已支持 PC)各種滾動(dòng)場(chǎng)景需求的插件,BetterScroll 是使用純 JavaScript 實(shí)現(xiàn)的,這意味著它是無(wú)依賴的。本文基于better-scroll 實(shí)現(xiàn)歌詞聯(lián)動(dòng)功能,感興趣的朋友跟隨小編一起看看吧2020-05-05

