Vue Expert — Series 2

Preview — 3 of 10 questions

When does this global handler fire, compared to a component's own onErrorCaptured?

javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.errorHandler = (err, instance, info) => {
  console.error('Global error handler:', err, info)
  reportToMonitoring(err)
}

app.mount('#app')
Aapp.config.errorHandler fires for every error, always before any component's onErrorCaptured hooks get a chance to run
Bapp.config.errorHandler only catches errors thrown directly inside main.js, not errors from any mounted component
CBoth fire simultaneously for every error, in an unspecified order
Dapp.config.errorHandler is the app-wide fallback: it only receives an error after it has propagated past every onErrorCaptured hook up the component tree (i.e. none of them returned false to stop it) — it's the last line of defense, not a first interceptor

Why is triggerRef(state) necessary after this mutation, when a plain ref() wouldn't need it?

javascript
import { shallowRef, triggerRef } from 'vue'

const state = shallowRef({ count: 0, label: 'initial' })

function mutateDeep() {
  state.value.count++          // mutates a nested property
  // template/watchers don't update yet — why?
  triggerRef(state)             // manually force dependents to re-run
}
AshallowRef only tracks reactivity on the .value reference itself — replacing state.value entirely would trigger updates automatically, but mutating a property inside the current object (state.value.count++) is invisible to a shallow ref's tracking, since its inner object isn't made deeply reactive. triggerRef() manually forces dependents to re-run despite that
BtriggerRef() is required after every single .value assignment on any ref, shallow or not
CshallowRef doesn't support .value mutation at all — state.value.count++ silently does nothing, triggerRef() retroactively applies the change
DtriggerRef() converts a shallowRef into a fully deep, regular ref permanently

What does defineSlots() provide here that plain slot usage (without it) wouldn't, in a TypeScript project?

javascript
<!-- DataTable.vue -->
<script setup lang="ts">
defineSlots<{
  row(props: { item: { id: number; name: string }; index: number }): any
  empty(): any
}>()
</script>

<template>
  <template v-if="items.length === 0">
    <slot name="empty" />
  </template>
  <template v-else>
    <slot v-for="(item, index) in items" name="row" :item="item" :index="index" />
  </template>
</template>
AdefineSlots() is required at runtime — without it, the <slot> elements in the template silently fail to render anything
BdefineSlots() restricts which slot names a consumer is allowed to use — passing an undeclared slot name throws a runtime error
CdefineSlots() is purely a compile-time TypeScript macro: it gives editor/type-checker support for the slot props a consumer receives when writing <template #row="{ item, index }">, without changing any runtime behavior — item and index get proper autocomplete and type errors if misused
DdefineSlots() automatically generates a fallback UI for any slot that isn't provided by the consumer

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.