Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/reactivity-markraw-for-non-reactive.md
1---2title: Use markRaw() for Objects That Should Never Be Reactive3impact: MEDIUM4impactDescription: Library instances, DOM nodes, and complex objects cause overhead and bugs when wrapped in Vue proxies5type: efficiency6tags: [vue3, reactivity, markRaw, performance, external-libraries, dom]7---89# Use markRaw() for Objects That Should Never Be Reactive1011**Impact: MEDIUM** - Vue's `markRaw()` tells the reactivity system to never wrap an object in a Proxy. Use it for library instances, DOM nodes, class instances with internal state, and complex objects that Vue shouldn't track. This prevents unnecessary proxy overhead and avoids subtle bugs from double-proxying.1213Without `markRaw()`, placing these objects inside reactive state causes Vue to wrap them in Proxies, which can break library internals, cause identity issues, and waste memory on objects that don't need change tracking.1415## Task Checklist1617- [ ] Use `markRaw()` for third-party library instances (maps, charts, editors)18- [ ] Use `markRaw()` for DOM elements stored in reactive state19- [ ] Use `markRaw()` for class instances that manage their own state20- [ ] Use `markRaw()` for large static data that will never change21- [ ] Remember: markRaw only affects the root level - nested objects may still be proxied2223**Incorrect:**24```javascript25import { reactive, ref } from 'vue'26import mapboxgl from 'mapbox-gl'27import * as monaco from 'monaco-editor'2829// WRONG: Library instances wrapped in Proxy30const state = reactive({31map: new mapboxgl.Map({ container: 'map' }), // Proxied!32editor: monaco.editor.create(element, {}), // Proxied!33})3435// Problems:36// 1. Library's internal this references may break37// 2. Unnecessary memory overhead38// 3. Methods may not work correctly through proxy39// 4. Performance degradation4041// WRONG: DOM elements in reactive state42const elements = reactive({43container: document.getElementById('app'), // Proxied DOM node!44})45```4647**Correct:**48```javascript49import { reactive, markRaw, shallowRef } from 'vue'50import mapboxgl from 'mapbox-gl'51import * as monaco from 'monaco-editor'5253// CORRECT: Mark library instances as raw54const state = reactive({55map: markRaw(new mapboxgl.Map({ container: 'map' })),56editor: markRaw(monaco.editor.create(element, {})),57})5859// CORRECT: Or use shallowRef for mutable references60const map = shallowRef(null)61onMounted(() => {62map.value = markRaw(new mapboxgl.Map({ container: 'map' }))63})6465// CORRECT: Large static data66const geoJsonData = markRaw(await fetch('/huge-geojson.json').then(r => r.json()))67const state = reactive({68mapData: geoJsonData // Won't be proxied69})70```7172**Class instances with internal state:**73```javascript74import { markRaw, reactive } from 'vue'7576class WebSocketManager {77constructor(url) {78this.socket = new WebSocket(url)79this.listeners = new Map()80}8182on(event, callback) {83this.listeners.set(event, callback)84}85}8687// CORRECT: Mark class instance88const wsManager = markRaw(new WebSocketManager('ws://example.com'))8990const state = reactive({91connection: wsManager // Won't be proxied92})9394// Can still use the instance normally95state.connection.on('message', handleMessage)96```9798**Gotcha: markRaw only affects root level:**99```javascript100import { markRaw, reactive } from 'vue'101102const rawObject = markRaw({103nested: { value: 1 } // This nested object is NOT marked raw104})105106const state = reactive({107data: rawObject108})109110// rawObject itself won't be proxied111// But if you access nested objects through a reactive parent:112const container = reactive({ raw: rawObject })113// container.raw.nested might still be proxied in some cases114115// SAFER: Use shallowRef for the container116import { shallowRef } from 'vue'117const safeContainer = shallowRef(rawObject)118```119120**Combining with shallowRef for best results:**121```javascript122import { shallowRef, markRaw, onMounted, onUnmounted } from 'vue'123124// Pattern: shallowRef + markRaw for external library instances125export function useMapbox(containerId) {126const map = shallowRef(null)127128onMounted(() => {129const instance = new mapboxgl.Map({130container: containerId,131style: 'mapbox://styles/mapbox/streets-v11'132})133134// Mark raw to prevent any proxy wrapping135map.value = markRaw(instance)136})137138onUnmounted(() => {139map.value?.remove()140})141142return { map }143}144```145146## Reference147- [Vue.js markRaw() API](https://vuejs.org/api/reactivity-advanced.html#markraw)148- [Vue.js Reducing Reactivity Overhead](https://vuejs.org/guide/best-practices/performance.html#reduce-reactivity-overhead-for-large-immutable-structures)149- [Vue.js Reactivity in Depth](https://vuejs.org/guide/extras/reactivity-in-depth.html)150