50 companion flashcards · AI-assisted study content · Open the deck →
This deck is designed for developers who already have a working knowledge of Vue.js and want to sharpen their understanding of the framework's more nuanced APIs and patterns. The cards dive into advanced reactivity helpers like shallowReactive and triggerRef, lifecycle and rendering hooks such as onRenderTracked, and the inner workings of component composition with defineComponent and PropType. You'll also find questions on transitions, slot prop destructuring, route navigation guards, and how to support custom v-model modifiers.
Because the topics lean toward Vue's internal APIs and edge cases, this deck is best suited for intermediate to advanced Vue developers, or for anyone preparing for a technical interview or building a complex application where these features come up. If you're still getting comfortable with the basics of components, directives, and the Options or Composition APIs, you may want to build that foundation first before working through these cards.
Since these questions cover specific function names, props, and behaviors rather than broad concepts, spaced repetition works especially well here. Try reviewing a small batch each day rather than cramming, and make a habit of writing a tiny code snippet or reading the relevant Vue docs whenever a card feels unfamiliar. Linking each flashcard to a real piece of source code in your mind will make the answers stick far longer than rote memorization.
Vue 3's reactivity system is the foundation for everything you build, and choosing the right primitive keeps components clean and predictable. The ref() function wraps primitive values and single object references, exposing them through a .value accessor so reads and writes are tracked uniformly. The reactive() helper, by contrast, takes an object and makes its properties reactive directly so you can read and write them without .value. A common pitfall is destructuring a reactive object, because pulling out a property into a local variable severs the reactive link with the source. The toRefs() utility solves this by converting each property into a linked ref, so destructuring preserves reactivity across the rest of the component.
Beyond plain state, Vue offers tools for derived values and side effects. A computed property is a cached reactive value derived from other reactive sources; it only recomputes when its dependencies actually change, which makes it the right tool for transforming existing state into a new value. When you need side effects such as API calls, persistence, or logging, watch() is a better fit because it explicitly observes sources and reacts to changes, whereas computed is for derivation rather than effects. watchEffect() is an even more automatic cousin that runs immediately and tracks every reactive dependency it touches during execution. After mutating reactive state, the DOM is not always updated synchronously, so nextTick() lets you wait for Vue to finish applying pending updates before measuring or further interacting with the DOM.
For cases where deep tracking is unnecessary or expensive, Vue exposes lighter alternatives. shallowReactive() creates a reactive object in which only the top-level properties are tracked, while nested objects remain non-reactive unless they are wrapped separately. This is useful for large objects or third-party structures where deep tracking would be wasteful. When working with a shallowRef, mutating the inner value does not automatically trigger updates because the reference itself has not changed. Calling triggerRef() manually notifies Vue that a change has occurred, allowing subscribers to react as expected.
Type safety and clean APIs become essential as Vue apps grow, and Vue provides several helpers for both at the component boundary. Wrapping a component with defineComponent() improves TypeScript inference across props, emits, computed values, and option fields, which pays off the moment any consumer of the component is itself typed. For complex prop shapes such as arrays of objects or discriminated unions, the PropType<T> helper lets you describe types in the Options API in a way the compiler understands. Inside <script setup>, the compiler macros defineProps() and defineEmits() declare props and event signatures with concise syntax, while defineExpose() explicitly exposes selected methods or refs to a parent that uses a template ref.
Clear event contracts matter as much as types. Beyond declaring what events a component can emit, you can attach validation functions to the emits option keyed by event name, so invalid payloads surface as warnings during development. When a parent uses v-model with modifiers such as .capitalize, Vue generates a modelModifiers prop on the child; reading that prop and branching on its flags lets the child apply the right behavior, such as transforming the value before emitting it back. Slot APIs follow a similar pattern of explicitness. On the parent side, you can destructure slot props with v-slot="{ item, index }" or the shorter #default="{ item, index }" so a component binds only the values it actually consumes.
Some tools are aimed at framework and library authors more than everyday app developers. getCurrentInstance() returns the currently active component instance, which is mostly useful when building plugins, render-function libraries, or other advanced internals where you need to reach into Vue's machinery. For most day-to-day code, registering things globally through the application instance keeps the surface area familiar: app.component('MyName', MyComponent) makes a component available everywhere in the app, while app.directive('focus', { mounted(el) { el.focus(); } }) installs a custom directive that Vue applies wherever you write v-focus. These patterns keep registration in one place and components themselves free of registration ceremony.
Vue includes several built-in components that solve structural problems templates alone cannot handle cleanly. <Teleport> renders a component's DOM output somewhere else in the document entirely, which is ideal for modals, toasts, tooltips, and other overlay UI that would otherwise be constrained by ancestor CSS such as overflow or stacking contexts. <KeepAlive> wraps dynamic components so that when one is switched out, its state is cached and can be seamlessly restored when it is brought back, sparing you the work of re-fetching data or re-running setup. <Suspense> coordinates asynchronous setup across nested components, emitting lifecycle events around its fallback and resolved states so you can build coordinated loading UIs without bespoke plumbing for each case.
Not every DOM question needs a new component. v-show and v-if both conditionally render UI but in very different ways. v-show toggles the CSS display of an element while leaving it in the DOM, which is cheap to flip repeatedly. v-if adds or removes the element entirely, which means it pays the full mount and unmount cost and is better when the condition rarely changes or when the off branch is heavy. The .prop modifier on v-bind forces Vue to set a DOM property instead of an HTML attribute, which matters when the attribute and property diverge, such as binding to innerHTML or to custom element properties.
For the most dynamic cases, you can drop down to render functions. A render function is plain JavaScript that returns virtual nodes directly instead of going through a template, which is helpful for highly dynamic output, headless UI libraries, and composition patterns where templates would be awkward or impossible. The companion runtime API Vue.compile() turns a template string into a render function at runtime, blending the two styles when needed, such as when delivering templates from a server or letting users author their own layouts.
Vue's transition system hooks into ordinary CSS transitions and animations through a small set of well-known class names. There are six core classes that cover every stage of an element's enter and leave. The enter sequence is v-enter-from, v-enter-active, and v-enter-to, while the leave sequence is v-leave-from, v-leave-active, and v-leave-to. Naming a <Transition> swaps the v- prefix for your own (for example my-transition-enter-from), which lets multiple transitions coexist without colliding and keeps CSS namespaced to the feature they drive.
The most commonly tuned knob on <Transition> is mode, which controls how an entering element and a leaving element overlap. With mode="out-in", Vue waits for the leaving element to finish its transition before inserting the entering element, producing a clear "one then the other" cadence that often feels more orderly than simultaneous crossfades. Other modes, or omitting mode altogether, produce different choreography, but out-in is the safest default when both elements occupy the same visual space and a simultaneous swap would visibly overlap.
Lists have their own rules, and the central one is the key attribute on items rendered with v-for. Keys tell Vue the identity of each element so it can preserve them across moves, insertions, and removals rather than tearing down and rebuilding the DOM each time. Stable, unique keys prevent reuse bugs such as broken form state, flickering transitions, and stale event listeners. Choosing a key whose value stays tied to the item's identity (usually a database id rather than the array index) is a small habit with outsized correctness benefits.
Routing is where many Vue applications earn their behavior, and Vue Router offers layered hooks for controlling navigation. router.beforeResolve is a global guard that runs after in-component navigation guards and async route components have resolved but before navigation is confirmed, which makes it a strong place for final checks such as permission or data readiness. router.afterEach fires only after a navigation has successfully completed and cannot change its outcome; it is most often used for analytics, logging, or page-level cleanup. Navigation guards in general are useful whenever you need to block, redirect, or prepare for a route change, whether for auth, unsaved data, permissions, or preloading data.
Performance and clarity both improve when you treat route shapes intentionally. Lazy loading a route means the component is imported only when that route is activated, shrinking the initial bundle and speeding up first load. It also helps to distinguish route params from query params: route params are part of the URL path and typically identify a resource (such as /users/:id), while query params modify how that resource is presented (such as /users?sort=asc&page=2). Encoding the relationship this way makes URLs shareable, bookmarkable, and predictable.
For shared application state, Pinia is the recommended store. A Pinia store is a centralized reactive module composed of state, actions, and derived values, with structure, tooling, traceability, and cleaner testing than ad-hoc global objects offer. For smaller, scoped sharing, Vue's built-in provide and inject let values flow through the component tree without prop drilling, though the tradeoff is that data flow becomes less explicit when used too liberally. For faster first paint and better crawlability, static site generation (SSG) pre-renders pages to HTML at build time. The server-side counterpart is server-side rendering, where the matching client concern is hydration: Vue attaches reactivity and event listeners to the server-rendered HTML on the client. Hydration mismatch errors happen when the server and client output diverge, typically because of random values, time-based content, or browser-only state being rendered into the initial tree.
When reactivity misbehaves, Vue exposes dedicated hooks to help you see what is happening. onRenderTracked reports every reactive dependency the component tracks during render, while onRenderTriggered reports which dependency caused a re-render. Together these debug hooks are invaluable when a component updates too often or unexpectedly, because they tell you exactly which pieces of state the reactivity system is paying attention to and which one tipped the schedule. Used sparingly during development, they cut the time spent staring at reproduction steps in half.
Performance in Vue is largely a matter of not doing unnecessary reactive work. Good habits include choosing stable, unique keys for list items, memoizing expensive derivations (either through computed or careful caching), and avoiding reactive wrapping for data that does not need it, such as large configuration blobs or third-party instances. For very large lists, virtualization keeps the rendered DOM count bounded as the user scrolls, so only what's on screen pays the mount cost. Combined with shallowRef and triggerRef() patterns for inner mutations, these choices keep large interactive surfaces responsive.
The same outward-looking mindset applies to tests. A well-tested Vue component asserts rendered behavior and emitted effects from the user's perspective rather than coupling to implementation details like which component owns which piece of state or how internal helpers are wired. Combined with the broader API surface (render functions built via Vue.compile() for runtime-compiled templates, and the layout machinery of Teleport, KeepAlive, and Suspense covered earlier), these habits make a Vue application easier to evolve and reason about as features are layered in.
v-enter-from, v-enter-active, v-enter-to, v-leave-from, v-leave-active, and v-leave-to.Drill this topic
50 flashcards on Vue Cards — free, no signup needed to start.
Study Vue Cards flashcardsLearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.