[{"data":1,"prerenderedAt":2605},["ShallowReactive",2],{"page-\u002Fvue\u002F08-lifecycle-hooks":3},{"id":4,"title":5,"body":6,"description":2598,"extension":2599,"meta":2600,"navigation":82,"path":2601,"seo":2602,"stem":2603,"__hash__":2604},"content\u002Fvue\u002F08-lifecycle-hooks.md","Vue 3 Engineering Reference — Lifecycle Hooks",{"type":7,"value":8,"toc":2586},"minimark",[9,14,19,309,313,602,606,846,850,1102,1106,2582],[10,11,13],"h1",{"id":12},"_08-lifecycle-hooks","08 — Lifecycle Hooks",[15,16,18],"h2",{"id":17},"the-complete-lifecycle-execution-order","The Complete Lifecycle — Execution Order",[20,21,24],"code-wrapper",{"filename":22,"language":23},"lifecycle-order.ts","typescript",[25,26,30],"pre",{"className":27,"code":28,"language":23,"meta":29,"style":29},"language-typescript shiki shiki-themes github-light github-dark","import {\n  onBeforeMount, onMounted, onBeforeUpdate, onUpdated,\n  onBeforeUnmount, onUnmounted, onActivated, onDeactivated,\n  onErrorCaptured, onServerPrefetch, ref\n} from 'vue'\n\n\u002F\u002F ── Full lifecycle sequence (Composition API names): ────\n\u002F\u002F\n\u002F\u002F 1.  setup() runs                    — Composition API entry, before \"created\"\n\u002F\u002F 2.  onBeforeMount                   — DOM not yet mounted\n\u002F\u002F 3.  DOM mounted                     — Vue creates the DOM tree\n\u002F\u002F 4.  onMounted                       — DOM is accessible, refs are populated\n\u002F\u002F 5.  ── Reactive state changes ──\n\u002F\u002F 6.  onBeforeUpdate                  — before DOM re-render\n\u002F\u002F 7.  DOM patched                     — Vue updates the DOM\n\u002F\u002F 8.  onUpdated                       — after DOM patch\n\u002F\u002F 9.  ── Component unmounts ──\n\u002F\u002F 10. onBeforeUnmount                 — cleanup before teardown\n\u002F\u002F 11. Component destroyed             — Vue removes DOM + disposes effects\n\u002F\u002F 12. onUnmounted                     — final cleanup, all effects disposed\n\n\u002F\u002F ── KeepAlive adds two hooks: ──────────────────────────\n\u002F\u002F    onActivated  — component re-activated (inserted from cache)\n\u002F\u002F    onDeactivated — component deactivated (cached, not destroyed)\n\n\u002F\u002F ── Error handling: ────────────────────────────────────\n\u002F\u002F    onErrorCaptured — catches errors from descendant components\n\u002F\u002F      (render, lifecycle hooks, watchers, setup of descendants)\n\n\u002F\u002F ── SSR-only: ──────────────────────────────────────────\n\u002F\u002F    onServerPrefetch — runs on server during SSR, resolved before render\n\n\u002F\u002F ── Every hook is registration-based, not override-based: ──\n\u002F\u002F You can call onMounted() multiple times — ALL registered callbacks fire in order.\n\u002F\u002F (Unlike Options API's mounted() which is a single method.)\nonMounted(() => console.log('mounted callback 1'))\nonMounted(() => console.log('mounted callback 2'))\n\u002F\u002F Both fire, in registration order.\n","",[31,32,33,46,52,58,64,77,84,91,97,103,109,115,121,127,133,139,145,151,157,163,169,174,180,186,192,197,203,209,215,220,226,232,237,243,249,255,283,303],"code",{"__ignoreMap":29},[34,35,38,42],"span",{"class":36,"line":37},"line",1,[34,39,41],{"class":40},"svdQ7","import",[34,43,45],{"class":44},"ssxIu"," {\n",[34,47,49],{"class":36,"line":48},2,[34,50,51],{"class":44},"  onBeforeMount, onMounted, onBeforeUpdate, onUpdated,\n",[34,53,55],{"class":36,"line":54},3,[34,56,57],{"class":44},"  onBeforeUnmount, onUnmounted, onActivated, onDeactivated,\n",[34,59,61],{"class":36,"line":60},4,[34,62,63],{"class":44},"  onErrorCaptured, onServerPrefetch, ref\n",[34,65,67,70,73],{"class":36,"line":66},5,[34,68,69],{"class":44},"} ",[34,71,72],{"class":40},"from",[34,74,76],{"class":75},"sJ6F3"," 'vue'\n",[34,78,80],{"class":36,"line":79},6,[34,81,83],{"emptyLinePlaceholder":82},true,"\n",[34,85,87],{"class":36,"line":86},7,[34,88,90],{"class":89},"sdCPZ","\u002F\u002F ── Full lifecycle sequence (Composition API names): ────\n",[34,92,94],{"class":36,"line":93},8,[34,95,96],{"class":89},"\u002F\u002F\n",[34,98,100],{"class":36,"line":99},9,[34,101,102],{"class":89},"\u002F\u002F 1.  setup() runs                    — Composition API entry, before \"created\"\n",[34,104,106],{"class":36,"line":105},10,[34,107,108],{"class":89},"\u002F\u002F 2.  onBeforeMount                   — DOM not yet mounted\n",[34,110,112],{"class":36,"line":111},11,[34,113,114],{"class":89},"\u002F\u002F 3.  DOM mounted                     — Vue creates the DOM tree\n",[34,116,118],{"class":36,"line":117},12,[34,119,120],{"class":89},"\u002F\u002F 4.  onMounted                       — DOM is accessible, refs are populated\n",[34,122,124],{"class":36,"line":123},13,[34,125,126],{"class":89},"\u002F\u002F 5.  ── Reactive state changes ──\n",[34,128,130],{"class":36,"line":129},14,[34,131,132],{"class":89},"\u002F\u002F 6.  onBeforeUpdate                  — before DOM re-render\n",[34,134,136],{"class":36,"line":135},15,[34,137,138],{"class":89},"\u002F\u002F 7.  DOM patched                     — Vue updates the DOM\n",[34,140,142],{"class":36,"line":141},16,[34,143,144],{"class":89},"\u002F\u002F 8.  onUpdated                       — after DOM patch\n",[34,146,148],{"class":36,"line":147},17,[34,149,150],{"class":89},"\u002F\u002F 9.  ── Component unmounts ──\n",[34,152,154],{"class":36,"line":153},18,[34,155,156],{"class":89},"\u002F\u002F 10. onBeforeUnmount                 — cleanup before teardown\n",[34,158,160],{"class":36,"line":159},19,[34,161,162],{"class":89},"\u002F\u002F 11. Component destroyed             — Vue removes DOM + disposes effects\n",[34,164,166],{"class":36,"line":165},20,[34,167,168],{"class":89},"\u002F\u002F 12. onUnmounted                     — final cleanup, all effects disposed\n",[34,170,172],{"class":36,"line":171},21,[34,173,83],{"emptyLinePlaceholder":82},[34,175,177],{"class":36,"line":176},22,[34,178,179],{"class":89},"\u002F\u002F ── KeepAlive adds two hooks: ──────────────────────────\n",[34,181,183],{"class":36,"line":182},23,[34,184,185],{"class":89},"\u002F\u002F    onActivated  — component re-activated (inserted from cache)\n",[34,187,189],{"class":36,"line":188},24,[34,190,191],{"class":89},"\u002F\u002F    onDeactivated — component deactivated (cached, not destroyed)\n",[34,193,195],{"class":36,"line":194},25,[34,196,83],{"emptyLinePlaceholder":82},[34,198,200],{"class":36,"line":199},26,[34,201,202],{"class":89},"\u002F\u002F ── Error handling: ────────────────────────────────────\n",[34,204,206],{"class":36,"line":205},27,[34,207,208],{"class":89},"\u002F\u002F    onErrorCaptured — catches errors from descendant components\n",[34,210,212],{"class":36,"line":211},28,[34,213,214],{"class":89},"\u002F\u002F      (render, lifecycle hooks, watchers, setup of descendants)\n",[34,216,218],{"class":36,"line":217},29,[34,219,83],{"emptyLinePlaceholder":82},[34,221,223],{"class":36,"line":222},30,[34,224,225],{"class":89},"\u002F\u002F ── SSR-only: ──────────────────────────────────────────\n",[34,227,229],{"class":36,"line":228},31,[34,230,231],{"class":89},"\u002F\u002F    onServerPrefetch — runs on server during SSR, resolved before render\n",[34,233,235],{"class":36,"line":234},32,[34,236,83],{"emptyLinePlaceholder":82},[34,238,240],{"class":36,"line":239},33,[34,241,242],{"class":89},"\u002F\u002F ── Every hook is registration-based, not override-based: ──\n",[34,244,246],{"class":36,"line":245},34,[34,247,248],{"class":89},"\u002F\u002F You can call onMounted() multiple times — ALL registered callbacks fire in order.\n",[34,250,252],{"class":36,"line":251},35,[34,253,254],{"class":89},"\u002F\u002F (Unlike Options API's mounted() which is a single method.)\n",[34,256,258,262,265,268,271,274,277,280],{"class":36,"line":257},36,[34,259,261],{"class":260},"sIsaT","onMounted",[34,263,264],{"class":44},"(() ",[34,266,267],{"class":40},"=>",[34,269,270],{"class":44}," console.",[34,272,273],{"class":260},"log",[34,275,276],{"class":44},"(",[34,278,279],{"class":75},"'mounted callback 1'",[34,281,282],{"class":44},"))\n",[34,284,286,288,290,292,294,296,298,301],{"class":36,"line":285},37,[34,287,261],{"class":260},[34,289,264],{"class":44},[34,291,267],{"class":40},[34,293,270],{"class":44},[34,295,273],{"class":260},[34,297,276],{"class":44},[34,299,300],{"class":75},"'mounted callback 2'",[34,302,282],{"class":44},[34,304,306],{"class":36,"line":305},38,[34,307,308],{"class":89},"\u002F\u002F Both fire, in registration order.\n",[15,310,312],{"id":311},"onmounted-dom-measurement-and-third-party-init","onMounted — DOM Measurement and Third-Party Init",[20,314,317],{"filename":315,"language":316},"ChartInit.vue","vue",[25,318,321],{"className":319,"code":320,"language":316,"meta":29,"style":29},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nimport { ref, onMounted, onBeforeUnmount, shallowRef } from 'vue'\nimport Chart from 'chart.js\u002Fauto'\n\nconst canvasRef = ref(null)\n\u002F\u002F ── shallowRef: holds the Chart instance without deep reactivity ──\n\u002F\u002F Chart.js instances are complex objects — reactive() wrapping breaks them.\nconst chart = shallowRef(null)\n\nonMounted(() => {\n  \u002F\u002F ── DOM is ready: canvasRef.value is now the \u003Ccanvas> element ──\n  \u002F\u002F Before onMounted, canvasRef.value is null (DOM not created yet).\n  chart.value = new Chart(canvasRef.value, {\n    type: 'bar',\n    data: { labels: ['A', 'B'], datasets: [{ data: [1, 2] }] },\n  })\n})\n\nonBeforeUnmount(() => {\n  \u002F\u002F ── Cleanup: destroy chart instance to free canvas memory ──\n  \u002F\u002F onBeforeUnmount runs while the component is still fully functional\n  \u002F\u002F (refs, state intact). onUnmounted runs after teardown.\n  chart.value?.destroy()\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ccanvas ref=\"canvasRef\" \u002F>\n\u003C\u002Ftemplate>\n",[31,322,323,338,349,361,365,388,393,398,416,420,430,435,440,457,468,496,501,506,510,521,526,531,536,547,551,560,564,573,594],{"__ignoreMap":29},[34,324,325,328,332,335],{"class":36,"line":37},[34,326,327],{"class":44},"\u003C",[34,329,331],{"class":330},"sk71V","script",[34,333,334],{"class":260}," setup",[34,336,337],{"class":44},">\n",[34,339,340,342,345,347],{"class":36,"line":48},[34,341,41],{"class":40},[34,343,344],{"class":44}," { ref, onMounted, onBeforeUnmount, shallowRef } ",[34,346,72],{"class":40},[34,348,76],{"class":75},[34,350,351,353,356,358],{"class":36,"line":54},[34,352,41],{"class":40},[34,354,355],{"class":44}," Chart ",[34,357,72],{"class":40},[34,359,360],{"class":75}," 'chart.js\u002Fauto'\n",[34,362,363],{"class":36,"line":60},[34,364,83],{"emptyLinePlaceholder":82},[34,366,367,370,374,377,380,382,385],{"class":36,"line":66},[34,368,369],{"class":40},"const",[34,371,373],{"class":372},"snvgF"," canvasRef",[34,375,376],{"class":40}," =",[34,378,379],{"class":260}," ref",[34,381,276],{"class":44},[34,383,384],{"class":372},"null",[34,386,387],{"class":44},")\n",[34,389,390],{"class":36,"line":79},[34,391,392],{"class":89},"\u002F\u002F ── shallowRef: holds the Chart instance without deep reactivity ──\n",[34,394,395],{"class":36,"line":86},[34,396,397],{"class":89},"\u002F\u002F Chart.js instances are complex objects — reactive() wrapping breaks them.\n",[34,399,400,402,405,407,410,412,414],{"class":36,"line":93},[34,401,369],{"class":40},[34,403,404],{"class":372}," chart",[34,406,376],{"class":40},[34,408,409],{"class":260}," shallowRef",[34,411,276],{"class":44},[34,413,384],{"class":372},[34,415,387],{"class":44},[34,417,418],{"class":36,"line":99},[34,419,83],{"emptyLinePlaceholder":82},[34,421,422,424,426,428],{"class":36,"line":105},[34,423,261],{"class":260},[34,425,264],{"class":44},[34,427,267],{"class":40},[34,429,45],{"class":44},[34,431,432],{"class":36,"line":111},[34,433,434],{"class":89},"  \u002F\u002F ── DOM is ready: canvasRef.value is now the \u003Ccanvas> element ──\n",[34,436,437],{"class":36,"line":117},[34,438,439],{"class":89},"  \u002F\u002F Before onMounted, canvasRef.value is null (DOM not created yet).\n",[34,441,442,445,448,451,454],{"class":36,"line":123},[34,443,444],{"class":44},"  chart.value ",[34,446,447],{"class":40},"=",[34,449,450],{"class":40}," new",[34,452,453],{"class":260}," Chart",[34,455,456],{"class":44},"(canvasRef.value, {\n",[34,458,459,462,465],{"class":36,"line":129},[34,460,461],{"class":44},"    type: ",[34,463,464],{"class":75},"'bar'",[34,466,467],{"class":44},",\n",[34,469,470,473,476,479,482,485,488,490,493],{"class":36,"line":135},[34,471,472],{"class":44},"    data: { labels: [",[34,474,475],{"class":75},"'A'",[34,477,478],{"class":44},", ",[34,480,481],{"class":75},"'B'",[34,483,484],{"class":44},"], datasets: [{ data: [",[34,486,487],{"class":372},"1",[34,489,478],{"class":44},[34,491,492],{"class":372},"2",[34,494,495],{"class":44},"] }] },\n",[34,497,498],{"class":36,"line":141},[34,499,500],{"class":44},"  })\n",[34,502,503],{"class":36,"line":147},[34,504,505],{"class":44},"})\n",[34,507,508],{"class":36,"line":153},[34,509,83],{"emptyLinePlaceholder":82},[34,511,512,515,517,519],{"class":36,"line":159},[34,513,514],{"class":260},"onBeforeUnmount",[34,516,264],{"class":44},[34,518,267],{"class":40},[34,520,45],{"class":44},[34,522,523],{"class":36,"line":165},[34,524,525],{"class":89},"  \u002F\u002F ── Cleanup: destroy chart instance to free canvas memory ──\n",[34,527,528],{"class":36,"line":171},[34,529,530],{"class":89},"  \u002F\u002F onBeforeUnmount runs while the component is still fully functional\n",[34,532,533],{"class":36,"line":176},[34,534,535],{"class":89},"  \u002F\u002F (refs, state intact). onUnmounted runs after teardown.\n",[34,537,538,541,544],{"class":36,"line":182},[34,539,540],{"class":44},"  chart.value?.",[34,542,543],{"class":260},"destroy",[34,545,546],{"class":44},"()\n",[34,548,549],{"class":36,"line":188},[34,550,505],{"class":44},[34,552,553,556,558],{"class":36,"line":194},[34,554,555],{"class":44},"\u003C\u002F",[34,557,331],{"class":330},[34,559,337],{"class":44},[34,561,562],{"class":36,"line":199},[34,563,83],{"emptyLinePlaceholder":82},[34,565,566,568,571],{"class":36,"line":205},[34,567,327],{"class":44},[34,569,570],{"class":330},"template",[34,572,337],{"class":44},[34,574,575,578,581,583,585,588,592],{"class":36,"line":211},[34,576,577],{"class":44},"  \u003C",[34,579,580],{"class":330},"canvas",[34,582,379],{"class":260},[34,584,447],{"class":44},[34,586,587],{"class":75},"\"canvasRef\"",[34,589,591],{"class":590},"sMKGj"," \u002F",[34,593,337],{"class":44},[34,595,596,598,600],{"class":36,"line":217},[34,597,555],{"class":44},[34,599,570],{"class":330},[34,601,337],{"class":44},[15,603,605],{"id":604},"onbeforeupdate-onupdated-avoiding-infinite-loops","onBeforeUpdate \u002F onUpdated — Avoiding Infinite Loops",[20,607,609],{"filename":608,"language":316},"UpdateLoopTrap.vue",[25,610,612],{"className":319,"code":611,"language":316,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref, onUpdated, onBeforeUpdate } from 'vue'\n\nconst items = ref([])\n\n\u002F\u002F ── onBeforeUpdate: read DOM BEFORE the patch ──────────\n\u002F\u002F Useful for saving scroll position or measuring before changes.\nonBeforeUpdate(() => {\n  \u002F\u002F DOM still shows the OLD state — measure before Vue patches it\n  scrollPosition.value = listEl.value?.scrollTop\n})\n\n\u002F\u002F ❌ WRONG: mutating state in onUpdated causes infinite loop\nonUpdated(() => {\n  \u002F\u002F This fires AFTER every DOM patch. If you mutate reactive state here,\n  \u002F\u002F Vue re-renders → fires onUpdated again → infinite loop.\n  items.value.push(Date.now())  \u002F\u002F DON'T DO THIS\n})\n\n\u002F\u002F ✅ CORRECT: onUpdated is for DOM reads, not state writes\nonUpdated(() => {\n  \u002F\u002F Read-only DOM operations are safe:\n  if (listEl.value) {\n    const isScrolledToBottom =\n      listEl.value.scrollTop + listEl.value.clientHeight >= listEl.value.scrollHeight\n    if (isScrolledToBottom) emit('scroll-bottom')\n  }\n})\n\u003C\u002Fscript>\n",[31,613,614,624,635,639,653,657,662,667,678,683,693,697,701,706,717,722,727,747,751,755,760,770,775,783,794,811,829,834,838],{"__ignoreMap":29},[34,615,616,618,620,622],{"class":36,"line":37},[34,617,327],{"class":44},[34,619,331],{"class":330},[34,621,334],{"class":260},[34,623,337],{"class":44},[34,625,626,628,631,633],{"class":36,"line":48},[34,627,41],{"class":40},[34,629,630],{"class":44}," { ref, onUpdated, onBeforeUpdate } ",[34,632,72],{"class":40},[34,634,76],{"class":75},[34,636,637],{"class":36,"line":54},[34,638,83],{"emptyLinePlaceholder":82},[34,640,641,643,646,648,650],{"class":36,"line":60},[34,642,369],{"class":40},[34,644,645],{"class":372}," items",[34,647,376],{"class":40},[34,649,379],{"class":260},[34,651,652],{"class":44},"([])\n",[34,654,655],{"class":36,"line":66},[34,656,83],{"emptyLinePlaceholder":82},[34,658,659],{"class":36,"line":79},[34,660,661],{"class":89},"\u002F\u002F ── onBeforeUpdate: read DOM BEFORE the patch ──────────\n",[34,663,664],{"class":36,"line":86},[34,665,666],{"class":89},"\u002F\u002F Useful for saving scroll position or measuring before changes.\n",[34,668,669,672,674,676],{"class":36,"line":93},[34,670,671],{"class":260},"onBeforeUpdate",[34,673,264],{"class":44},[34,675,267],{"class":40},[34,677,45],{"class":44},[34,679,680],{"class":36,"line":99},[34,681,682],{"class":89},"  \u002F\u002F DOM still shows the OLD state — measure before Vue patches it\n",[34,684,685,688,690],{"class":36,"line":105},[34,686,687],{"class":44},"  scrollPosition.value ",[34,689,447],{"class":40},[34,691,692],{"class":44}," listEl.value?.scrollTop\n",[34,694,695],{"class":36,"line":111},[34,696,505],{"class":44},[34,698,699],{"class":36,"line":117},[34,700,83],{"emptyLinePlaceholder":82},[34,702,703],{"class":36,"line":123},[34,704,705],{"class":89},"\u002F\u002F ❌ WRONG: mutating state in onUpdated causes infinite loop\n",[34,707,708,711,713,715],{"class":36,"line":129},[34,709,710],{"class":260},"onUpdated",[34,712,264],{"class":44},[34,714,267],{"class":40},[34,716,45],{"class":44},[34,718,719],{"class":36,"line":135},[34,720,721],{"class":89},"  \u002F\u002F This fires AFTER every DOM patch. If you mutate reactive state here,\n",[34,723,724],{"class":36,"line":141},[34,725,726],{"class":89},"  \u002F\u002F Vue re-renders → fires onUpdated again → infinite loop.\n",[34,728,729,732,735,738,741,744],{"class":36,"line":147},[34,730,731],{"class":44},"  items.value.",[34,733,734],{"class":260},"push",[34,736,737],{"class":44},"(Date.",[34,739,740],{"class":260},"now",[34,742,743],{"class":44},"())  ",[34,745,746],{"class":89},"\u002F\u002F DON'T DO THIS\n",[34,748,749],{"class":36,"line":153},[34,750,505],{"class":44},[34,752,753],{"class":36,"line":159},[34,754,83],{"emptyLinePlaceholder":82},[34,756,757],{"class":36,"line":165},[34,758,759],{"class":89},"\u002F\u002F ✅ CORRECT: onUpdated is for DOM reads, not state writes\n",[34,761,762,764,766,768],{"class":36,"line":171},[34,763,710],{"class":260},[34,765,264],{"class":44},[34,767,267],{"class":40},[34,769,45],{"class":44},[34,771,772],{"class":36,"line":176},[34,773,774],{"class":89},"  \u002F\u002F Read-only DOM operations are safe:\n",[34,776,777,780],{"class":36,"line":182},[34,778,779],{"class":40},"  if",[34,781,782],{"class":44}," (listEl.value) {\n",[34,784,785,788,791],{"class":36,"line":188},[34,786,787],{"class":40},"    const",[34,789,790],{"class":372}," isScrolledToBottom",[34,792,793],{"class":40}," =\n",[34,795,796,799,802,805,808],{"class":36,"line":194},[34,797,798],{"class":44},"      listEl.value.scrollTop ",[34,800,801],{"class":40},"+",[34,803,804],{"class":44}," listEl.value.clientHeight ",[34,806,807],{"class":40},">=",[34,809,810],{"class":44}," listEl.value.scrollHeight\n",[34,812,813,816,819,822,824,827],{"class":36,"line":199},[34,814,815],{"class":40},"    if",[34,817,818],{"class":44}," (isScrolledToBottom) ",[34,820,821],{"class":260},"emit",[34,823,276],{"class":44},[34,825,826],{"class":75},"'scroll-bottom'",[34,828,387],{"class":44},[34,830,831],{"class":36,"line":205},[34,832,833],{"class":44},"  }\n",[34,835,836],{"class":36,"line":211},[34,837,505],{"class":44},[34,839,840,842,844],{"class":36,"line":217},[34,841,555],{"class":44},[34,843,331],{"class":330},[34,845,337],{"class":44},[15,847,849],{"id":848},"onunmounted-resource-cleanup-checklist","onUnmounted — Resource Cleanup Checklist",[20,851,853],{"filename":852,"language":23},"cleanup.ts",[25,854,856],{"className":27,"code":855,"language":23,"meta":29,"style":29},"import { onUnmounted, onScopeDispose, ref } from 'vue'\n\n\u002F\u002F ── Everything registered externally must be cleaned up ──\n\u002F\u002F Rule: if you called `add`, you must call `remove` on unmount.\n\nonUnmounted(() => {\n  \u002F\u002F ── 1. Event listeners ──\n  window.removeEventListener('resize', resizeHandler)\n  document.removeEventListener('keydown', keyHandler)\n\n  \u002F\u002F ── 2. Timers ──\n  clearInterval(pollInterval)\n  clearTimeout(debounceTimer)\n\n  \u002F\u002F ── 3. WebSockets \u002F EventSource ──\n  socket.close()\n  eventSource.close()\n\n  \u002F\u002F ── 4. Observers ──\n  intersectionObserver.disconnect()\n  resizeObserver.disconnect()\n\n  \u002F\u002F ── 5. Third-party instances ──\n  chartInstance.destroy()\n  editorInstance.dispose()\n\n  \u002F\u002F ── 6. Animations ──\n  cancelAnimationFrame(rafId)\n\n  \u002F\u002F ── 7. AbortController (cancel pending fetches) ──\n  abortController.abort()\n})\n\n\u002F\u002F ── Preferred: use onScopeDispose inside composables ──\n\u002F\u002F Composables register their own cleanup, parent doesn't need to know details.\n\u002F\u002F If the composable uses onScopeDispose, onUnmounted is redundant for that resource.\n",[31,857,858,869,873,878,883,887,898,903,919,934,938,943,951,959,963,968,978,987,991,996,1006,1015,1019,1024,1033,1043,1047,1052,1060,1064,1069,1079,1083,1087,1092,1097],{"__ignoreMap":29},[34,859,860,862,865,867],{"class":36,"line":37},[34,861,41],{"class":40},[34,863,864],{"class":44}," { onUnmounted, onScopeDispose, ref } ",[34,866,72],{"class":40},[34,868,76],{"class":75},[34,870,871],{"class":36,"line":48},[34,872,83],{"emptyLinePlaceholder":82},[34,874,875],{"class":36,"line":54},[34,876,877],{"class":89},"\u002F\u002F ── Everything registered externally must be cleaned up ──\n",[34,879,880],{"class":36,"line":60},[34,881,882],{"class":89},"\u002F\u002F Rule: if you called `add`, you must call `remove` on unmount.\n",[34,884,885],{"class":36,"line":66},[34,886,83],{"emptyLinePlaceholder":82},[34,888,889,892,894,896],{"class":36,"line":79},[34,890,891],{"class":260},"onUnmounted",[34,893,264],{"class":44},[34,895,267],{"class":40},[34,897,45],{"class":44},[34,899,900],{"class":36,"line":86},[34,901,902],{"class":89},"  \u002F\u002F ── 1. Event listeners ──\n",[34,904,905,908,911,913,916],{"class":36,"line":93},[34,906,907],{"class":44},"  window.",[34,909,910],{"class":260},"removeEventListener",[34,912,276],{"class":44},[34,914,915],{"class":75},"'resize'",[34,917,918],{"class":44},", resizeHandler)\n",[34,920,921,924,926,928,931],{"class":36,"line":99},[34,922,923],{"class":44},"  document.",[34,925,910],{"class":260},[34,927,276],{"class":44},[34,929,930],{"class":75},"'keydown'",[34,932,933],{"class":44},", keyHandler)\n",[34,935,936],{"class":36,"line":105},[34,937,83],{"emptyLinePlaceholder":82},[34,939,940],{"class":36,"line":111},[34,941,942],{"class":89},"  \u002F\u002F ── 2. Timers ──\n",[34,944,945,948],{"class":36,"line":117},[34,946,947],{"class":260},"  clearInterval",[34,949,950],{"class":44},"(pollInterval)\n",[34,952,953,956],{"class":36,"line":123},[34,954,955],{"class":260},"  clearTimeout",[34,957,958],{"class":44},"(debounceTimer)\n",[34,960,961],{"class":36,"line":129},[34,962,83],{"emptyLinePlaceholder":82},[34,964,965],{"class":36,"line":135},[34,966,967],{"class":89},"  \u002F\u002F ── 3. WebSockets \u002F EventSource ──\n",[34,969,970,973,976],{"class":36,"line":141},[34,971,972],{"class":44},"  socket.",[34,974,975],{"class":260},"close",[34,977,546],{"class":44},[34,979,980,983,985],{"class":36,"line":147},[34,981,982],{"class":44},"  eventSource.",[34,984,975],{"class":260},[34,986,546],{"class":44},[34,988,989],{"class":36,"line":153},[34,990,83],{"emptyLinePlaceholder":82},[34,992,993],{"class":36,"line":159},[34,994,995],{"class":89},"  \u002F\u002F ── 4. Observers ──\n",[34,997,998,1001,1004],{"class":36,"line":165},[34,999,1000],{"class":44},"  intersectionObserver.",[34,1002,1003],{"class":260},"disconnect",[34,1005,546],{"class":44},[34,1007,1008,1011,1013],{"class":36,"line":171},[34,1009,1010],{"class":44},"  resizeObserver.",[34,1012,1003],{"class":260},[34,1014,546],{"class":44},[34,1016,1017],{"class":36,"line":176},[34,1018,83],{"emptyLinePlaceholder":82},[34,1020,1021],{"class":36,"line":182},[34,1022,1023],{"class":89},"  \u002F\u002F ── 5. Third-party instances ──\n",[34,1025,1026,1029,1031],{"class":36,"line":188},[34,1027,1028],{"class":44},"  chartInstance.",[34,1030,543],{"class":260},[34,1032,546],{"class":44},[34,1034,1035,1038,1041],{"class":36,"line":194},[34,1036,1037],{"class":44},"  editorInstance.",[34,1039,1040],{"class":260},"dispose",[34,1042,546],{"class":44},[34,1044,1045],{"class":36,"line":199},[34,1046,83],{"emptyLinePlaceholder":82},[34,1048,1049],{"class":36,"line":205},[34,1050,1051],{"class":89},"  \u002F\u002F ── 6. Animations ──\n",[34,1053,1054,1057],{"class":36,"line":211},[34,1055,1056],{"class":260},"  cancelAnimationFrame",[34,1058,1059],{"class":44},"(rafId)\n",[34,1061,1062],{"class":36,"line":217},[34,1063,83],{"emptyLinePlaceholder":82},[34,1065,1066],{"class":36,"line":222},[34,1067,1068],{"class":89},"  \u002F\u002F ── 7. AbortController (cancel pending fetches) ──\n",[34,1070,1071,1074,1077],{"class":36,"line":228},[34,1072,1073],{"class":44},"  abortController.",[34,1075,1076],{"class":260},"abort",[34,1078,546],{"class":44},[34,1080,1081],{"class":36,"line":234},[34,1082,505],{"class":44},[34,1084,1085],{"class":36,"line":239},[34,1086,83],{"emptyLinePlaceholder":82},[34,1088,1089],{"class":36,"line":245},[34,1090,1091],{"class":89},"\u002F\u002F ── Preferred: use onScopeDispose inside composables ──\n",[34,1093,1094],{"class":36,"line":251},[34,1095,1096],{"class":89},"\u002F\u002F Composables register their own cleanup, parent doesn't need to know details.\n",[34,1098,1099],{"class":36,"line":257},[34,1100,1101],{"class":89},"\u002F\u002F If the composable uses onScopeDispose, onUnmounted is redundant for that resource.\n",[15,1103,1105],{"id":1104},"keepalive-onactivated-ondeactivated","KeepAlive — onActivated \u002F onDeactivated",[20,1107,1109,1342,1490,1494,1802,1806,1964,1968,2099,2103,2221,2225,2228,2383],{"filename":1108,"language":316},"KeepAliveTabs.vue",[25,1110,1112],{"className":319,"code":1111,"language":316,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref, onMounted, onActivated, onDeactivated, onUnmounted } from 'vue'\n\n\u002F\u002F ── KeepAlive lifecycle: ────────────────────────────────\n\u002F\u002F First mount: onMounted → onActivated\n\u002F\u002F Tab switch away: onDeactivated (component stays in memory, DOM detached)\n\u002F\u002F Tab switch back: onActivated (component re-attached, state preserved)\n\u002F\u002F KeepAlive removed entirely: onDeactivated → onUnmounted\n\n\u002F\u002F ── onMounted fires ONCE even with KeepAlive ──\nonMounted(() => console.log('mounted — fires once'))\n\n\u002F\u002F ── onActivated fires on EVERY activation (including first mount) ──\nonActivated(() => {\n  \u002F\u002F ── Re-start polling, re-subscribe to events, resume video ──\n  \u002F\u002F This is where you \"resume\" after being cached.\n  startPolling()\n  window.addEventListener('visibilitychange', onVisible)\n})\n\n\u002F\u002F ── onDeactivated fires when cached (NOT destroyed) ──\nonDeactivated(() => {\n  \u002F\u002F ── Pause polling, unsubscribe, pause video ──\n  \u002F\u002F Component is detached from DOM but state is preserved.\n  stopPolling()\n  window.removeEventListener('visibilitychange', onVisible)\n})\n\n\u002F\u002F ── onUnmounted fires ONLY when KeepAlive is removed or max exceeded ──\nonUnmounted(() => {\n  \u002F\u002F Final cleanup — component is truly destroyed.\n  \u002F\u002F Fires after onDeactivated if the component is evicted from cache.\n})\n\u003C\u002Fscript>\n",[31,1113,1114,1124,1135,1139,1144,1149,1154,1159,1164,1168,1173,1192,1196,1201,1212,1217,1222,1229,1244,1248,1252,1257,1268,1273,1278,1285,1297,1301,1305,1310,1320,1325,1330,1334],{"__ignoreMap":29},[34,1115,1116,1118,1120,1122],{"class":36,"line":37},[34,1117,327],{"class":44},[34,1119,331],{"class":330},[34,1121,334],{"class":260},[34,1123,337],{"class":44},[34,1125,1126,1128,1131,1133],{"class":36,"line":48},[34,1127,41],{"class":40},[34,1129,1130],{"class":44}," { ref, onMounted, onActivated, onDeactivated, onUnmounted } ",[34,1132,72],{"class":40},[34,1134,76],{"class":75},[34,1136,1137],{"class":36,"line":54},[34,1138,83],{"emptyLinePlaceholder":82},[34,1140,1141],{"class":36,"line":60},[34,1142,1143],{"class":89},"\u002F\u002F ── KeepAlive lifecycle: ────────────────────────────────\n",[34,1145,1146],{"class":36,"line":66},[34,1147,1148],{"class":89},"\u002F\u002F First mount: onMounted → onActivated\n",[34,1150,1151],{"class":36,"line":79},[34,1152,1153],{"class":89},"\u002F\u002F Tab switch away: onDeactivated (component stays in memory, DOM detached)\n",[34,1155,1156],{"class":36,"line":86},[34,1157,1158],{"class":89},"\u002F\u002F Tab switch back: onActivated (component re-attached, state preserved)\n",[34,1160,1161],{"class":36,"line":93},[34,1162,1163],{"class":89},"\u002F\u002F KeepAlive removed entirely: onDeactivated → onUnmounted\n",[34,1165,1166],{"class":36,"line":99},[34,1167,83],{"emptyLinePlaceholder":82},[34,1169,1170],{"class":36,"line":105},[34,1171,1172],{"class":89},"\u002F\u002F ── onMounted fires ONCE even with KeepAlive ──\n",[34,1174,1175,1177,1179,1181,1183,1185,1187,1190],{"class":36,"line":111},[34,1176,261],{"class":260},[34,1178,264],{"class":44},[34,1180,267],{"class":40},[34,1182,270],{"class":44},[34,1184,273],{"class":260},[34,1186,276],{"class":44},[34,1188,1189],{"class":75},"'mounted — fires once'",[34,1191,282],{"class":44},[34,1193,1194],{"class":36,"line":117},[34,1195,83],{"emptyLinePlaceholder":82},[34,1197,1198],{"class":36,"line":123},[34,1199,1200],{"class":89},"\u002F\u002F ── onActivated fires on EVERY activation (including first mount) ──\n",[34,1202,1203,1206,1208,1210],{"class":36,"line":129},[34,1204,1205],{"class":260},"onActivated",[34,1207,264],{"class":44},[34,1209,267],{"class":40},[34,1211,45],{"class":44},[34,1213,1214],{"class":36,"line":135},[34,1215,1216],{"class":89},"  \u002F\u002F ── Re-start polling, re-subscribe to events, resume video ──\n",[34,1218,1219],{"class":36,"line":141},[34,1220,1221],{"class":89},"  \u002F\u002F This is where you \"resume\" after being cached.\n",[34,1223,1224,1227],{"class":36,"line":147},[34,1225,1226],{"class":260},"  startPolling",[34,1228,546],{"class":44},[34,1230,1231,1233,1236,1238,1241],{"class":36,"line":153},[34,1232,907],{"class":44},[34,1234,1235],{"class":260},"addEventListener",[34,1237,276],{"class":44},[34,1239,1240],{"class":75},"'visibilitychange'",[34,1242,1243],{"class":44},", onVisible)\n",[34,1245,1246],{"class":36,"line":159},[34,1247,505],{"class":44},[34,1249,1250],{"class":36,"line":165},[34,1251,83],{"emptyLinePlaceholder":82},[34,1253,1254],{"class":36,"line":171},[34,1255,1256],{"class":89},"\u002F\u002F ── onDeactivated fires when cached (NOT destroyed) ──\n",[34,1258,1259,1262,1264,1266],{"class":36,"line":176},[34,1260,1261],{"class":260},"onDeactivated",[34,1263,264],{"class":44},[34,1265,267],{"class":40},[34,1267,45],{"class":44},[34,1269,1270],{"class":36,"line":182},[34,1271,1272],{"class":89},"  \u002F\u002F ── Pause polling, unsubscribe, pause video ──\n",[34,1274,1275],{"class":36,"line":188},[34,1276,1277],{"class":89},"  \u002F\u002F Component is detached from DOM but state is preserved.\n",[34,1279,1280,1283],{"class":36,"line":194},[34,1281,1282],{"class":260},"  stopPolling",[34,1284,546],{"class":44},[34,1286,1287,1289,1291,1293,1295],{"class":36,"line":199},[34,1288,907],{"class":44},[34,1290,910],{"class":260},[34,1292,276],{"class":44},[34,1294,1240],{"class":75},[34,1296,1243],{"class":44},[34,1298,1299],{"class":36,"line":205},[34,1300,505],{"class":44},[34,1302,1303],{"class":36,"line":211},[34,1304,83],{"emptyLinePlaceholder":82},[34,1306,1307],{"class":36,"line":217},[34,1308,1309],{"class":89},"\u002F\u002F ── onUnmounted fires ONLY when KeepAlive is removed or max exceeded ──\n",[34,1311,1312,1314,1316,1318],{"class":36,"line":222},[34,1313,891],{"class":260},[34,1315,264],{"class":44},[34,1317,267],{"class":40},[34,1319,45],{"class":44},[34,1321,1322],{"class":36,"line":228},[34,1323,1324],{"class":89},"  \u002F\u002F Final cleanup — component is truly destroyed.\n",[34,1326,1327],{"class":36,"line":234},[34,1328,1329],{"class":89},"  \u002F\u002F Fires after onDeactivated if the component is evicted from cache.\n",[34,1331,1332],{"class":36,"line":239},[34,1333,505],{"class":44},[34,1335,1336,1338,1340],{"class":36,"line":245},[34,1337,555],{"class":44},[34,1339,331],{"class":330},[34,1341,337],{"class":44},[20,1343,1345],{"filename":1344,"language":316},"KeepAliveConfig.vue",[25,1346,1348],{"className":319,"code":1347,"language":316,"meta":29,"style":29},"\u003Ctemplate>\n  \u003C!-- ── KeepAlive props ── -->\n  \u003CKeepAlive\n    :include=\"['UserList', 'Settings']\"  \u003C!-- only cache components matching name -->\n    :exclude=\"['HeavyChart']\"             \u003C!-- never cache these -->\n    :max=\"5\"                              \u003C!-- LRU — keep max 5 instances -->\n  >\n    \u003Ccomponent :is=\"activeComponent\" \u002F>\n  \u003C\u002FKeepAlive>\n  \u003C!-- ── Component name matters: include\u002Fexclude match component `name` ── -->\n  \u003C!-- In \u003Cscript setup>, set name via: defineOptions({ name: 'UserList' }) -->\n\u003C\u002Ftemplate>\n",[31,1349,1350,1358,1363,1370,1422,1430,1438,1443,1462,1472,1477,1482],{"__ignoreMap":29},[34,1351,1352,1354,1356],{"class":36,"line":37},[34,1353,327],{"class":44},[34,1355,570],{"class":330},[34,1357,337],{"class":44},[34,1359,1360],{"class":36,"line":48},[34,1361,1362],{"class":89},"  \u003C!-- ── KeepAlive props ── -->\n",[34,1364,1365,1367],{"class":36,"line":54},[34,1366,577],{"class":44},[34,1368,1369],{"class":330},"KeepAlive\n",[34,1371,1372,1375,1378,1380,1383,1386,1389,1391,1394,1397,1399,1402,1405,1408,1411,1414,1417,1420],{"class":36,"line":60},[34,1373,1374],{"class":44},"    :",[34,1376,1377],{"class":260},"include",[34,1379,447],{"class":44},[34,1381,1382],{"class":75},"\"",[34,1384,1385],{"class":44},"[",[34,1387,1388],{"class":75},"'UserList'",[34,1390,478],{"class":44},[34,1392,1393],{"class":75},"'Settings'",[34,1395,1396],{"class":44},"]",[34,1398,1382],{"class":75},[34,1400,1401],{"class":590},"  \u003C!--",[34,1403,1404],{"class":260}," only",[34,1406,1407],{"class":260}," cache",[34,1409,1410],{"class":260}," components",[34,1412,1413],{"class":260}," matching",[34,1415,1416],{"class":260}," name",[34,1418,1419],{"class":260}," --",[34,1421,337],{"class":44},[34,1423,1424,1427],{"class":36,"line":66},[34,1425,1426],{"class":44},"    :exclude=\"['HeavyChart']\"             ",[34,1428,1429],{"class":89},"\u003C!-- never cache these -->\n",[34,1431,1432,1435],{"class":36,"line":79},[34,1433,1434],{"class":44},"    :max=\"5\"                              ",[34,1436,1437],{"class":89},"\u003C!-- LRU — keep max 5 instances -->\n",[34,1439,1440],{"class":36,"line":86},[34,1441,1442],{"class":44},"  >\n",[34,1444,1445,1448,1451,1454,1456,1459],{"class":36,"line":93},[34,1446,1447],{"class":44},"    \u003C",[34,1449,1450],{"class":330},"component",[34,1452,1453],{"class":260}," :is",[34,1455,447],{"class":44},[34,1457,1458],{"class":75},"\"activeComponent\"",[34,1460,1461],{"class":44}," \u002F>\n",[34,1463,1464,1467,1470],{"class":36,"line":99},[34,1465,1466],{"class":44},"  \u003C\u002F",[34,1468,1469],{"class":330},"KeepAlive",[34,1471,337],{"class":44},[34,1473,1474],{"class":36,"line":105},[34,1475,1476],{"class":89},"  \u003C!-- ── Component name matters: include\u002Fexclude match component `name` ── -->\n",[34,1478,1479],{"class":36,"line":111},[34,1480,1481],{"class":89},"  \u003C!-- In \u003Cscript setup>, set name via: defineOptions({ name: 'UserList' }) -->\n",[34,1483,1484,1486,1488],{"class":36,"line":117},[34,1485,555],{"class":44},[34,1487,570],{"class":330},[34,1489,337],{"class":44},[15,1491,1493],{"id":1492},"onerrorcaptured-error-boundary-pattern","onErrorCaptured — Error Boundary Pattern",[20,1495,1497],{"filename":1496,"language":316},"ErrorBoundary.vue",[25,1498,1500],{"className":319,"code":1499,"language":316,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref, onErrorCaptured } from 'vue'\n\nconst error = ref(null)\n\n\u002F\u002F ── onErrorCaptured: catches errors from ALL descendant components ──\n\u002F\u002F Fires for errors in: descendant render, lifecycle hooks, watchers, setup\n\u002F\u002F (e) error, (instance) component instance, (info) lifecycle hook name\nonErrorCaptured((err, instance, info) => {\n  console.error(`Error in ${instance?.$options?.name}:`, err, 'during', info)\n  error.value = err\n\n  \u002F\u002F ── Return value controls propagation: ──\n  return false  \u002F\u002F stop propagation — error does not reach parent's onErrorCaptured\n  \u002F\u002F return true (or undefined) — propagate to parent's error handler\n  \u002F\u002F ── This makes it an error boundary: catches and handles, doesn't rethrow ──\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"error\" class=\"error-boundary\">\n    \u003Ch2>Something went wrong\u003C\u002Fh2>\n    \u003Cp>{{ error.message }}\u003C\u002Fp>\n    \u003Cbutton @click=\"error = null\">Retry\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cslot v-else \u002F>  \u003C!-- child components render here -->\n\u003C\u002Ftemplate>\n",[31,1501,1502,1512,1523,1527,1544,1548,1553,1558,1563,1592,1630,1640,1644,1649,1660,1665,1670,1674,1682,1686,1694,1719,1732,1746,1768,1776,1794],{"__ignoreMap":29},[34,1503,1504,1506,1508,1510],{"class":36,"line":37},[34,1505,327],{"class":44},[34,1507,331],{"class":330},[34,1509,334],{"class":260},[34,1511,337],{"class":44},[34,1513,1514,1516,1519,1521],{"class":36,"line":48},[34,1515,41],{"class":40},[34,1517,1518],{"class":44}," { ref, onErrorCaptured } ",[34,1520,72],{"class":40},[34,1522,76],{"class":75},[34,1524,1525],{"class":36,"line":54},[34,1526,83],{"emptyLinePlaceholder":82},[34,1528,1529,1531,1534,1536,1538,1540,1542],{"class":36,"line":60},[34,1530,369],{"class":40},[34,1532,1533],{"class":372}," error",[34,1535,376],{"class":40},[34,1537,379],{"class":260},[34,1539,276],{"class":44},[34,1541,384],{"class":372},[34,1543,387],{"class":44},[34,1545,1546],{"class":36,"line":66},[34,1547,83],{"emptyLinePlaceholder":82},[34,1549,1550],{"class":36,"line":79},[34,1551,1552],{"class":89},"\u002F\u002F ── onErrorCaptured: catches errors from ALL descendant components ──\n",[34,1554,1555],{"class":36,"line":86},[34,1556,1557],{"class":89},"\u002F\u002F Fires for errors in: descendant render, lifecycle hooks, watchers, setup\n",[34,1559,1560],{"class":36,"line":93},[34,1561,1562],{"class":89},"\u002F\u002F (e) error, (instance) component instance, (info) lifecycle hook name\n",[34,1564,1565,1568,1571,1575,1577,1580,1582,1585,1588,1590],{"class":36,"line":99},[34,1566,1567],{"class":260},"onErrorCaptured",[34,1569,1570],{"class":44},"((",[34,1572,1574],{"class":1573},"sCrzJ","err",[34,1576,478],{"class":44},[34,1578,1579],{"class":1573},"instance",[34,1581,478],{"class":44},[34,1583,1584],{"class":1573},"info",[34,1586,1587],{"class":44},") ",[34,1589,267],{"class":40},[34,1591,45],{"class":44},[34,1593,1594,1597,1600,1602,1605,1607,1610,1613,1615,1618,1621,1624,1627],{"class":36,"line":105},[34,1595,1596],{"class":44},"  console.",[34,1598,1599],{"class":260},"error",[34,1601,276],{"class":44},[34,1603,1604],{"class":75},"`Error in ${",[34,1606,1579],{"class":44},[34,1608,1609],{"class":75},"?.",[34,1611,1612],{"class":44},"$options",[34,1614,1609],{"class":75},[34,1616,1617],{"class":44},"name",[34,1619,1620],{"class":75},"}:`",[34,1622,1623],{"class":44},", err, ",[34,1625,1626],{"class":75},"'during'",[34,1628,1629],{"class":44},", info)\n",[34,1631,1632,1635,1637],{"class":36,"line":111},[34,1633,1634],{"class":44},"  error.value ",[34,1636,447],{"class":40},[34,1638,1639],{"class":44}," err\n",[34,1641,1642],{"class":36,"line":117},[34,1643,83],{"emptyLinePlaceholder":82},[34,1645,1646],{"class":36,"line":123},[34,1647,1648],{"class":89},"  \u002F\u002F ── Return value controls propagation: ──\n",[34,1650,1651,1654,1657],{"class":36,"line":129},[34,1652,1653],{"class":40},"  return",[34,1655,1656],{"class":372}," false",[34,1658,1659],{"class":89},"  \u002F\u002F stop propagation — error does not reach parent's onErrorCaptured\n",[34,1661,1662],{"class":36,"line":135},[34,1663,1664],{"class":89},"  \u002F\u002F return true (or undefined) — propagate to parent's error handler\n",[34,1666,1667],{"class":36,"line":141},[34,1668,1669],{"class":89},"  \u002F\u002F ── This makes it an error boundary: catches and handles, doesn't rethrow ──\n",[34,1671,1672],{"class":36,"line":147},[34,1673,505],{"class":44},[34,1675,1676,1678,1680],{"class":36,"line":153},[34,1677,555],{"class":44},[34,1679,331],{"class":330},[34,1681,337],{"class":44},[34,1683,1684],{"class":36,"line":159},[34,1685,83],{"emptyLinePlaceholder":82},[34,1687,1688,1690,1692],{"class":36,"line":165},[34,1689,327],{"class":44},[34,1691,570],{"class":330},[34,1693,337],{"class":44},[34,1695,1696,1698,1701,1704,1706,1709,1712,1714,1717],{"class":36,"line":171},[34,1697,577],{"class":44},[34,1699,1700],{"class":330},"div",[34,1702,1703],{"class":260}," v-if",[34,1705,447],{"class":44},[34,1707,1708],{"class":75},"\"error\"",[34,1710,1711],{"class":260}," class",[34,1713,447],{"class":44},[34,1715,1716],{"class":75},"\"error-boundary\"",[34,1718,337],{"class":44},[34,1720,1721,1723,1725,1728,1730],{"class":36,"line":176},[34,1722,1447],{"class":44},[34,1724,15],{"class":330},[34,1726,1727],{"class":44},">Something went wrong\u003C\u002F",[34,1729,15],{"class":330},[34,1731,337],{"class":44},[34,1733,1734,1736,1739,1742,1744],{"class":36,"line":182},[34,1735,1447],{"class":44},[34,1737,1738],{"class":330},"p",[34,1740,1741],{"class":44},">{{ error.message }}\u003C\u002F",[34,1743,1738],{"class":330},[34,1745,337],{"class":44},[34,1747,1748,1750,1753,1756,1758,1761,1764,1766],{"class":36,"line":188},[34,1749,1447],{"class":44},[34,1751,1752],{"class":330},"button",[34,1754,1755],{"class":260}," @click",[34,1757,447],{"class":44},[34,1759,1760],{"class":75},"\"error = null\"",[34,1762,1763],{"class":44},">Retry\u003C\u002F",[34,1765,1752],{"class":330},[34,1767,337],{"class":44},[34,1769,1770,1772,1774],{"class":36,"line":194},[34,1771,1466],{"class":44},[34,1773,1700],{"class":330},[34,1775,337],{"class":44},[34,1777,1778,1780,1783,1786,1788,1791],{"class":36,"line":199},[34,1779,577],{"class":44},[34,1781,1782],{"class":330},"slot",[34,1784,1785],{"class":260}," v-else",[34,1787,591],{"class":590},[34,1789,1790],{"class":44},">  ",[34,1792,1793],{"class":89},"\u003C!-- child components render here -->\n",[34,1795,1796,1798,1800],{"class":36,"line":205},[34,1797,555],{"class":44},[34,1799,570],{"class":330},[34,1801,337],{"class":44},[15,1803,1805],{"id":1804},"onserverprefetch-ssr-data-preloading","onServerPrefetch — SSR Data Preloading",[20,1807,1809],{"filename":1808,"language":23},"server-prefetch.ts",[25,1810,1812],{"className":27,"code":1811,"language":23,"meta":29,"style":29},"import { ref, onServerPrefetch } from 'vue'\n\nconst data = ref(null)\n\n\u002F\u002F ── onServerPrefetch: runs ONLY on the server during SSR ──\n\u002F\u002F The callback returns a Promise — the server waits for it to resolve\n\u002F\u002F before rendering the component's HTML.\n\u002F\u002F On the client (hydration), this hook is SKIPPED — client uses the\n\u002F\u002F server-provided state instead of re-fetching.\n\nonServerPrefetch(async () => {\n  const res = await fetch('\u002Fapi\u002Finitial-data')\n  data.value = await res.json()\n  \u002F\u002F Server renders with data already populated → no client-side loading flash.\n})\n\n\u002F\u002F ── When to use: ────────────────────────────────────────\n\u002F\u002F Critical above-the-fold data that must be in the initial HTML (SEO, perceived perf).\n\u002F\u002F For non-critical data, prefer client-side fetch with useFetch() composable.\n",[31,1813,1814,1825,1829,1846,1850,1855,1860,1865,1870,1875,1879,1896,1919,1936,1941,1945,1949,1954,1959],{"__ignoreMap":29},[34,1815,1816,1818,1821,1823],{"class":36,"line":37},[34,1817,41],{"class":40},[34,1819,1820],{"class":44}," { ref, onServerPrefetch } ",[34,1822,72],{"class":40},[34,1824,76],{"class":75},[34,1826,1827],{"class":36,"line":48},[34,1828,83],{"emptyLinePlaceholder":82},[34,1830,1831,1833,1836,1838,1840,1842,1844],{"class":36,"line":54},[34,1832,369],{"class":40},[34,1834,1835],{"class":372}," data",[34,1837,376],{"class":40},[34,1839,379],{"class":260},[34,1841,276],{"class":44},[34,1843,384],{"class":372},[34,1845,387],{"class":44},[34,1847,1848],{"class":36,"line":60},[34,1849,83],{"emptyLinePlaceholder":82},[34,1851,1852],{"class":36,"line":66},[34,1853,1854],{"class":89},"\u002F\u002F ── onServerPrefetch: runs ONLY on the server during SSR ──\n",[34,1856,1857],{"class":36,"line":79},[34,1858,1859],{"class":89},"\u002F\u002F The callback returns a Promise — the server waits for it to resolve\n",[34,1861,1862],{"class":36,"line":86},[34,1863,1864],{"class":89},"\u002F\u002F before rendering the component's HTML.\n",[34,1866,1867],{"class":36,"line":93},[34,1868,1869],{"class":89},"\u002F\u002F On the client (hydration), this hook is SKIPPED — client uses the\n",[34,1871,1872],{"class":36,"line":99},[34,1873,1874],{"class":89},"\u002F\u002F server-provided state instead of re-fetching.\n",[34,1876,1877],{"class":36,"line":105},[34,1878,83],{"emptyLinePlaceholder":82},[34,1880,1881,1884,1886,1889,1892,1894],{"class":36,"line":111},[34,1882,1883],{"class":260},"onServerPrefetch",[34,1885,276],{"class":44},[34,1887,1888],{"class":40},"async",[34,1890,1891],{"class":44}," () ",[34,1893,267],{"class":40},[34,1895,45],{"class":44},[34,1897,1898,1901,1904,1906,1909,1912,1914,1917],{"class":36,"line":117},[34,1899,1900],{"class":40},"  const",[34,1902,1903],{"class":372}," res",[34,1905,376],{"class":40},[34,1907,1908],{"class":40}," await",[34,1910,1911],{"class":260}," fetch",[34,1913,276],{"class":44},[34,1915,1916],{"class":75},"'\u002Fapi\u002Finitial-data'",[34,1918,387],{"class":44},[34,1920,1921,1924,1926,1928,1931,1934],{"class":36,"line":123},[34,1922,1923],{"class":44},"  data.value ",[34,1925,447],{"class":40},[34,1927,1908],{"class":40},[34,1929,1930],{"class":44}," res.",[34,1932,1933],{"class":260},"json",[34,1935,546],{"class":44},[34,1937,1938],{"class":36,"line":129},[34,1939,1940],{"class":89},"  \u002F\u002F Server renders with data already populated → no client-side loading flash.\n",[34,1942,1943],{"class":36,"line":135},[34,1944,505],{"class":44},[34,1946,1947],{"class":36,"line":141},[34,1948,83],{"emptyLinePlaceholder":82},[34,1950,1951],{"class":36,"line":147},[34,1952,1953],{"class":89},"\u002F\u002F ── When to use: ────────────────────────────────────────\n",[34,1955,1956],{"class":36,"line":153},[34,1957,1958],{"class":89},"\u002F\u002F Critical above-the-fold data that must be in the initial HTML (SEO, perceived perf).\n",[34,1960,1961],{"class":36,"line":159},[34,1962,1963],{"class":89},"\u002F\u002F For non-critical data, prefer client-side fetch with useFetch() composable.\n",[15,1965,1967],{"id":1966},"tips-tricks","💡 Tips & Tricks",[20,1969,1971],{"filename":1970,"language":23},"tips.ts",[25,1972,1974],{"className":27,"code":1973,"language":23,"meta":29,"style":29},"\u002F\u002F ── 1. Multiple onMounted calls — all fire in registration order ──\nonMounted(() => console.log('first'))  \u002F\u002F fires first\nonMounted(() => console.log('second')) \u002F\u002F fires second\n\u002F\u002F Unlike Options API's single mounted() method.\n\n\u002F\u002F ── 2. Hooks must be called synchronously in setup() ──\n\u002F\u002F ❌ onMounted(() => ...) inside setTimeout — registration too late, won't fire\n\u002F\u002F ✅ Always register hooks at the top level of setup() or \u003Cscript setup>\n\n\u002F\u002F ── 3. onBeforeUnmount vs onUnmounted ──\n\u002F\u002F onBeforeUnmount: component still fully functional (refs, state intact)\n\u002F\u002F   → use for cleanup that needs to READ component state\n\u002F\u002F onUnmounted: effects already disposed, refs may be null\n\u002F\u002F   → use for final logging, pure side-effects\n\n\u002F\u002F ── 4. Template refs are null before onMounted ──\n\u002F\u002F ref(null) in setup → populated during mount → accessible in onMounted\n\u002F\u002F Guard: if (ref.value) { ... } in case of v-if conditional rendering\n",[31,1975,1976,1981,2004,2027,2032,2036,2041,2046,2051,2055,2060,2065,2070,2075,2080,2084,2089,2094],{"__ignoreMap":29},[34,1977,1978],{"class":36,"line":37},[34,1979,1980],{"class":89},"\u002F\u002F ── 1. Multiple onMounted calls — all fire in registration order ──\n",[34,1982,1983,1985,1987,1989,1991,1993,1995,1998,2001],{"class":36,"line":48},[34,1984,261],{"class":260},[34,1986,264],{"class":44},[34,1988,267],{"class":40},[34,1990,270],{"class":44},[34,1992,273],{"class":260},[34,1994,276],{"class":44},[34,1996,1997],{"class":75},"'first'",[34,1999,2000],{"class":44},"))  ",[34,2002,2003],{"class":89},"\u002F\u002F fires first\n",[34,2005,2006,2008,2010,2012,2014,2016,2018,2021,2024],{"class":36,"line":54},[34,2007,261],{"class":260},[34,2009,264],{"class":44},[34,2011,267],{"class":40},[34,2013,270],{"class":44},[34,2015,273],{"class":260},[34,2017,276],{"class":44},[34,2019,2020],{"class":75},"'second'",[34,2022,2023],{"class":44},")) ",[34,2025,2026],{"class":89},"\u002F\u002F fires second\n",[34,2028,2029],{"class":36,"line":60},[34,2030,2031],{"class":89},"\u002F\u002F Unlike Options API's single mounted() method.\n",[34,2033,2034],{"class":36,"line":66},[34,2035,83],{"emptyLinePlaceholder":82},[34,2037,2038],{"class":36,"line":79},[34,2039,2040],{"class":89},"\u002F\u002F ── 2. Hooks must be called synchronously in setup() ──\n",[34,2042,2043],{"class":36,"line":86},[34,2044,2045],{"class":89},"\u002F\u002F ❌ onMounted(() => ...) inside setTimeout — registration too late, won't fire\n",[34,2047,2048],{"class":36,"line":93},[34,2049,2050],{"class":89},"\u002F\u002F ✅ Always register hooks at the top level of setup() or \u003Cscript setup>\n",[34,2052,2053],{"class":36,"line":99},[34,2054,83],{"emptyLinePlaceholder":82},[34,2056,2057],{"class":36,"line":105},[34,2058,2059],{"class":89},"\u002F\u002F ── 3. onBeforeUnmount vs onUnmounted ──\n",[34,2061,2062],{"class":36,"line":111},[34,2063,2064],{"class":89},"\u002F\u002F onBeforeUnmount: component still fully functional (refs, state intact)\n",[34,2066,2067],{"class":36,"line":117},[34,2068,2069],{"class":89},"\u002F\u002F   → use for cleanup that needs to READ component state\n",[34,2071,2072],{"class":36,"line":123},[34,2073,2074],{"class":89},"\u002F\u002F onUnmounted: effects already disposed, refs may be null\n",[34,2076,2077],{"class":36,"line":129},[34,2078,2079],{"class":89},"\u002F\u002F   → use for final logging, pure side-effects\n",[34,2081,2082],{"class":36,"line":135},[34,2083,83],{"emptyLinePlaceholder":82},[34,2085,2086],{"class":36,"line":141},[34,2087,2088],{"class":89},"\u002F\u002F ── 4. Template refs are null before onMounted ──\n",[34,2090,2091],{"class":36,"line":147},[34,2092,2093],{"class":89},"\u002F\u002F ref(null) in setup → populated during mount → accessible in onMounted\n",[34,2095,2096],{"class":36,"line":153},[34,2097,2098],{"class":89},"\u002F\u002F Guard: if (ref.value) { ... } in case of v-if conditional rendering\n",[15,2100,2102],{"id":2101},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,2104,2106],{"filename":2105,"language":23},"edge-cases.ts",[25,2107,2109],{"className":27,"code":2108,"language":23,"meta":29,"style":29},"\u002F\u002F ── 1. onUpdated fires after EVERY re-render, including child re-renders ──\n\u002F\u002F If a child component updates, the parent's onUpdated fires too.\n\u002F\u002F Don't use onUpdated for logic that should only run on specific state changes.\n\n\u002F\u002F ── 2. onMounted fires before child components are fully mounted ──\n\u002F\u002F Parent's onMounted fires BEFORE child's onMounted (inside-out for mounted).\n\u002F\u002F If parent needs child to be mounted, use nextTick() or a child-emitted event.\n\n\u002F\u002F ── 3. KeepAlive + onMounted: onMounted fires ONCE, onActivated fires every time ──\n\u002F\u002F Common bug: putting event listeners in onMounted with KeepAlive.\n\u002F\u002F Component is deactivated (listener stays) → activated (no re-registration) → listener works.\n\u002F\u002F But if listener is removed in onUnmounted (not onDeactivated), it's never removed while cached.\n\n\u002F\u002F ── 4. Hooks registered in async callbacks don't work ──\n\u002F\u002F ❌ onMounted(() => setTimeout(() => onUpdated(...), 0))  — onUpdated is too late\n\u002F\u002F Hooks must be registered during the synchronous setup() execution.\n\n\u002F\u002F ── 5. onErrorCaptured doesn't catch errors in event handlers ──\n\u002F\u002F Only catches errors in: render, setup, lifecycle hooks, watchers.\n\u002F\u002F Event handler errors go to app.config.errorHandler, not onErrorCaptured.\n\n\u002F\u002F ── 6. onServerPrefetch is server-only — skipped on client ──\n\u002F\u002F Don't put client-side logic in onServerPrefetch — it won't run during hydration.\n",[31,2110,2111,2116,2121,2126,2130,2135,2140,2145,2149,2154,2159,2164,2169,2173,2178,2183,2188,2192,2197,2202,2207,2211,2216],{"__ignoreMap":29},[34,2112,2113],{"class":36,"line":37},[34,2114,2115],{"class":89},"\u002F\u002F ── 1. onUpdated fires after EVERY re-render, including child re-renders ──\n",[34,2117,2118],{"class":36,"line":48},[34,2119,2120],{"class":89},"\u002F\u002F If a child component updates, the parent's onUpdated fires too.\n",[34,2122,2123],{"class":36,"line":54},[34,2124,2125],{"class":89},"\u002F\u002F Don't use onUpdated for logic that should only run on specific state changes.\n",[34,2127,2128],{"class":36,"line":60},[34,2129,83],{"emptyLinePlaceholder":82},[34,2131,2132],{"class":36,"line":66},[34,2133,2134],{"class":89},"\u002F\u002F ── 2. onMounted fires before child components are fully mounted ──\n",[34,2136,2137],{"class":36,"line":79},[34,2138,2139],{"class":89},"\u002F\u002F Parent's onMounted fires BEFORE child's onMounted (inside-out for mounted).\n",[34,2141,2142],{"class":36,"line":86},[34,2143,2144],{"class":89},"\u002F\u002F If parent needs child to be mounted, use nextTick() or a child-emitted event.\n",[34,2146,2147],{"class":36,"line":93},[34,2148,83],{"emptyLinePlaceholder":82},[34,2150,2151],{"class":36,"line":99},[34,2152,2153],{"class":89},"\u002F\u002F ── 3. KeepAlive + onMounted: onMounted fires ONCE, onActivated fires every time ──\n",[34,2155,2156],{"class":36,"line":105},[34,2157,2158],{"class":89},"\u002F\u002F Common bug: putting event listeners in onMounted with KeepAlive.\n",[34,2160,2161],{"class":36,"line":111},[34,2162,2163],{"class":89},"\u002F\u002F Component is deactivated (listener stays) → activated (no re-registration) → listener works.\n",[34,2165,2166],{"class":36,"line":117},[34,2167,2168],{"class":89},"\u002F\u002F But if listener is removed in onUnmounted (not onDeactivated), it's never removed while cached.\n",[34,2170,2171],{"class":36,"line":123},[34,2172,83],{"emptyLinePlaceholder":82},[34,2174,2175],{"class":36,"line":129},[34,2176,2177],{"class":89},"\u002F\u002F ── 4. Hooks registered in async callbacks don't work ──\n",[34,2179,2180],{"class":36,"line":135},[34,2181,2182],{"class":89},"\u002F\u002F ❌ onMounted(() => setTimeout(() => onUpdated(...), 0))  — onUpdated is too late\n",[34,2184,2185],{"class":36,"line":141},[34,2186,2187],{"class":89},"\u002F\u002F Hooks must be registered during the synchronous setup() execution.\n",[34,2189,2190],{"class":36,"line":147},[34,2191,83],{"emptyLinePlaceholder":82},[34,2193,2194],{"class":36,"line":153},[34,2195,2196],{"class":89},"\u002F\u002F ── 5. onErrorCaptured doesn't catch errors in event handlers ──\n",[34,2198,2199],{"class":36,"line":159},[34,2200,2201],{"class":89},"\u002F\u002F Only catches errors in: render, setup, lifecycle hooks, watchers.\n",[34,2203,2204],{"class":36,"line":165},[34,2205,2206],{"class":89},"\u002F\u002F Event handler errors go to app.config.errorHandler, not onErrorCaptured.\n",[34,2208,2209],{"class":36,"line":171},[34,2210,83],{"emptyLinePlaceholder":82},[34,2212,2213],{"class":36,"line":176},[34,2214,2215],{"class":89},"\u002F\u002F ── 6. onServerPrefetch is server-only — skipped on client ──\n",[34,2217,2218],{"class":36,"line":182},[34,2219,2220],{"class":89},"\u002F\u002F Don't put client-side logic in onServerPrefetch — it won't run during hydration.\n",[15,2222,2224],{"id":2223},"spot-the-bug","🧠 Spot the Bug",[1738,2226,2227],{},"A KeepAlive component's event listener persists even after the user navigates away.",[20,2229,2231],{"filename":2230,"language":316},"KeepAliveBug.vue",[25,2232,2234],{"className":319,"code":2233,"language":316,"meta":29,"style":29},"\u003Cscript setup>\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst position = ref(0)\n\nonMounted(() => {\n  window.addEventListener('scroll', (e) => {\n    position.value = window.scrollY\n  })\n})\n\nonUnmounted(() => {\n  \u002F\u002F ⚠️ This only fires when KeepAlive evicts the component (max exceeded or removed)\n  \u002F\u002F NOT when the user navigates to another tab (onDeactivated fires instead)\n  window.removeEventListener('scroll', handler)\n})\n\u003C\u002Fscript>\n",[31,2235,2236,2246,2257,2261,2279,2283,2293,2316,2326,2330,2334,2338,2348,2353,2358,2371,2375],{"__ignoreMap":29},[34,2237,2238,2240,2242,2244],{"class":36,"line":37},[34,2239,327],{"class":44},[34,2241,331],{"class":330},[34,2243,334],{"class":260},[34,2245,337],{"class":44},[34,2247,2248,2250,2253,2255],{"class":36,"line":48},[34,2249,41],{"class":40},[34,2251,2252],{"class":44}," { onMounted, onUnmounted, ref } ",[34,2254,72],{"class":40},[34,2256,76],{"class":75},[34,2258,2259],{"class":36,"line":54},[34,2260,83],{"emptyLinePlaceholder":82},[34,2262,2263,2265,2268,2270,2272,2274,2277],{"class":36,"line":60},[34,2264,369],{"class":40},[34,2266,2267],{"class":372}," position",[34,2269,376],{"class":40},[34,2271,379],{"class":260},[34,2273,276],{"class":44},[34,2275,2276],{"class":372},"0",[34,2278,387],{"class":44},[34,2280,2281],{"class":36,"line":66},[34,2282,83],{"emptyLinePlaceholder":82},[34,2284,2285,2287,2289,2291],{"class":36,"line":79},[34,2286,261],{"class":260},[34,2288,264],{"class":44},[34,2290,267],{"class":40},[34,2292,45],{"class":44},[34,2294,2295,2297,2299,2301,2304,2307,2310,2312,2314],{"class":36,"line":86},[34,2296,907],{"class":44},[34,2298,1235],{"class":260},[34,2300,276],{"class":44},[34,2302,2303],{"class":75},"'scroll'",[34,2305,2306],{"class":44},", (",[34,2308,2309],{"class":1573},"e",[34,2311,1587],{"class":44},[34,2313,267],{"class":40},[34,2315,45],{"class":44},[34,2317,2318,2321,2323],{"class":36,"line":93},[34,2319,2320],{"class":44},"    position.value ",[34,2322,447],{"class":40},[34,2324,2325],{"class":44}," window.scrollY\n",[34,2327,2328],{"class":36,"line":99},[34,2329,500],{"class":44},[34,2331,2332],{"class":36,"line":105},[34,2333,505],{"class":44},[34,2335,2336],{"class":36,"line":111},[34,2337,83],{"emptyLinePlaceholder":82},[34,2339,2340,2342,2344,2346],{"class":36,"line":117},[34,2341,891],{"class":260},[34,2343,264],{"class":44},[34,2345,267],{"class":40},[34,2347,45],{"class":44},[34,2349,2350],{"class":36,"line":123},[34,2351,2352],{"class":89},"  \u002F\u002F ⚠️ This only fires when KeepAlive evicts the component (max exceeded or removed)\n",[34,2354,2355],{"class":36,"line":129},[34,2356,2357],{"class":89},"  \u002F\u002F NOT when the user navigates to another tab (onDeactivated fires instead)\n",[34,2359,2360,2362,2364,2366,2368],{"class":36,"line":135},[34,2361,907],{"class":44},[34,2363,910],{"class":260},[34,2365,276],{"class":44},[34,2367,2303],{"class":75},[34,2369,2370],{"class":44},", handler)\n",[34,2372,2373],{"class":36,"line":141},[34,2374,505],{"class":44},[34,2376,2377,2379,2381],{"class":36,"line":147},[34,2378,555],{"class":44},[34,2380,331],{"class":330},[34,2382,337],{"class":44},[2384,2385,2386,2390,2402,2420,2564],"details",{},[2387,2388,2389],"summary",{},"Answer",[1738,2391,2392,2393,2395,2396,2398,2399,2401],{},"With ",[31,2394,1469],{},", navigating away fires ",[31,2397,1261],{},", not ",[31,2400,891],{},". The listener stays active while the component is cached, continuing to fire scroll handlers in the background — wasted CPU and potential state bugs on reactivation.",[1738,2403,2404,2408,2409,2411,2412,2414,2415,2411,2417,2419],{},[2405,2406,2407],"strong",{},"Fix"," — use ",[31,2410,1205],{},"\u002F",[31,2413,1261],{}," instead of ",[31,2416,261],{},[31,2418,891],{},":",[20,2421,2423],{"filename":2422,"language":316},"KeepAliveFixed.vue",[25,2424,2426],{"className":319,"code":2425,"language":316,"meta":29,"style":29},"\u003Cscript setup>\nimport { onActivated, onDeactivated, ref } from 'vue'\n\nconst position = ref(0)\n\nfunction handler() { position.value = window.scrollY }\n\nonActivated(() => {\n  window.addEventListener('scroll', handler)  \u002F\u002F re-register on every activation\n})\n\nonDeactivated(() => {\n  window.removeEventListener('scroll', handler)  \u002F\u002F clean up when cached\n})\n\u003C\u002Fscript>\n",[31,2427,2428,2438,2449,2453,2469,2473,2489,2493,2503,2519,2523,2527,2537,2552,2556],{"__ignoreMap":29},[34,2429,2430,2432,2434,2436],{"class":36,"line":37},[34,2431,327],{"class":44},[34,2433,331],{"class":330},[34,2435,334],{"class":260},[34,2437,337],{"class":44},[34,2439,2440,2442,2445,2447],{"class":36,"line":48},[34,2441,41],{"class":40},[34,2443,2444],{"class":44}," { onActivated, onDeactivated, ref } ",[34,2446,72],{"class":40},[34,2448,76],{"class":75},[34,2450,2451],{"class":36,"line":54},[34,2452,83],{"emptyLinePlaceholder":82},[34,2454,2455,2457,2459,2461,2463,2465,2467],{"class":36,"line":60},[34,2456,369],{"class":40},[34,2458,2267],{"class":372},[34,2460,376],{"class":40},[34,2462,379],{"class":260},[34,2464,276],{"class":44},[34,2466,2276],{"class":372},[34,2468,387],{"class":44},[34,2470,2471],{"class":36,"line":66},[34,2472,83],{"emptyLinePlaceholder":82},[34,2474,2475,2478,2481,2484,2486],{"class":36,"line":79},[34,2476,2477],{"class":40},"function",[34,2479,2480],{"class":260}," handler",[34,2482,2483],{"class":44},"() { position.value ",[34,2485,447],{"class":40},[34,2487,2488],{"class":44}," window.scrollY }\n",[34,2490,2491],{"class":36,"line":86},[34,2492,83],{"emptyLinePlaceholder":82},[34,2494,2495,2497,2499,2501],{"class":36,"line":93},[34,2496,1205],{"class":260},[34,2498,264],{"class":44},[34,2500,267],{"class":40},[34,2502,45],{"class":44},[34,2504,2505,2507,2509,2511,2513,2516],{"class":36,"line":99},[34,2506,907],{"class":44},[34,2508,1235],{"class":260},[34,2510,276],{"class":44},[34,2512,2303],{"class":75},[34,2514,2515],{"class":44},", handler)  ",[34,2517,2518],{"class":89},"\u002F\u002F re-register on every activation\n",[34,2520,2521],{"class":36,"line":105},[34,2522,505],{"class":44},[34,2524,2525],{"class":36,"line":111},[34,2526,83],{"emptyLinePlaceholder":82},[34,2528,2529,2531,2533,2535],{"class":36,"line":117},[34,2530,1261],{"class":260},[34,2532,264],{"class":44},[34,2534,267],{"class":40},[34,2536,45],{"class":44},[34,2538,2539,2541,2543,2545,2547,2549],{"class":36,"line":123},[34,2540,907],{"class":44},[34,2542,910],{"class":260},[34,2544,276],{"class":44},[34,2546,2303],{"class":75},[34,2548,2515],{"class":44},[34,2550,2551],{"class":89},"\u002F\u002F clean up when cached\n",[34,2553,2554],{"class":36,"line":129},[34,2555,505],{"class":44},[34,2557,2558,2560,2562],{"class":36,"line":135},[34,2559,555],{"class":44},[34,2561,331],{"class":330},[34,2563,337],{"class":44},[1738,2565,2566,2569,2570,478,2572,2411,2574,2576,2577,2411,2579,2581],{},[2405,2567,2568],{},"The lesson",": with ",[31,2571,1469],{},[31,2573,261],{},[31,2575,891],{}," fire only once (initial mount and final eviction). Use ",[31,2578,1205],{},[31,2580,1261],{}," for resources that should be active only while the component is visible.",[2583,2584,2585],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sMKGj, html code.shiki .sMKGj{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-github-dark:#FDAEB7;--shiki-github-dark-font-style:italic}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":29,"searchDepth":48,"depth":48,"links":2587},[2588,2589,2590,2591,2592,2593,2594,2595,2596,2597],{"id":17,"depth":48,"text":18},{"id":311,"depth":48,"text":312},{"id":604,"depth":48,"text":605},{"id":848,"depth":48,"text":849},{"id":1104,"depth":48,"text":1105},{"id":1492,"depth":48,"text":1493},{"id":1804,"depth":48,"text":1805},{"id":1966,"depth":48,"text":1967},{"id":2101,"depth":48,"text":2102},{"id":2223,"depth":48,"text":2224},"Full lifecycle sequence, setup-time vs mounted-time hooks, onUnmounted cleanup patterns, KeepAlive activation\u002Fdeactivation, error capture boundaries, and hook execution order guarantees.","md",{},"\u002Fvue\u002F08-lifecycle-hooks",{"title":5,"description":2598},"vue\u002F08-lifecycle-hooks","AyLOXLuLjd0RsRiRlDPeXeb3WdEzjYDOYBkG-hHUxa4",1789924655507]