Vue.js Pocket Book

Vue.js Pocket Book — Uplatz

50 in-depth cards • Wide layout • Readable examples • 20-question interview Q&A included

Section 1 — Core Foundations

1) What is Vue.js?

Vue is a progressive framework for building UIs. It combines a reactive data system, declarative templates, and component composition. Vue 3 introduced the Composition API, the new reactivity system (Proxies), and better TypeScript support.

<!-- CDN quick start -->
<script src="https://unpkg.com/vue@3"></script>
<div id="app">Hello {{ msg }}</div>
<script>
const { createApp, ref } = Vue;
createApp({ setup(){ const msg=ref('Vue'); return { msg } } }).mount('#app');
</script>

2) Declarative Templates

Vue templates compile to efficient render functions. Use directives like v-bind, v-on, v-if, v-for, and modifiers (.prevent, .stop) for expressive UIs.

<button :title="hint" @click.prevent="save">Save</button>
<li v-for="(u,i) in users" :key="u.id">{{ i+1 }}. {{ u.name }}</li>

3) Reactivity Basics

ref() wraps a reactive primitive; reactive() turns objects reactive. Access/assign via .value for refs; objects unwrap in templates.

const n = ref(0); const state = reactive({ open:false });
watch(n, (nv, ov) => console.log('changed', ov, '→', nv));

4) Single File Components (SFC)

.vue SFCs bundle template, script, and style. Use <script setup> to get concise Composition API syntax and better treeshaking.

<template><button @click="count++">{{ count }}</button></template>
<script setup>import { ref } from 'vue'; const count = ref(0);</script>

5) Props & Emits

Define props and emitted events for parent-child communication. Validate props with types; declare emits for better DX.

<script setup>
defineProps({ label:String, modelValue:Boolean });
const emit = defineEmits(['update:modelValue']);
const toggle = () => emit('update:modelValue', !modelValue);
</script>

6) Computed & Watch

computed() caches derived values until dependencies change. watch() reacts to changes with side-effects. Use watchEffect() for autoruns.

const full = computed(() => `${first.value} ${last.value}`);
watch(search, debounce(fetchList, 300));

7) Directives Deep Dive

Built-ins: v-if, v-show, v-for, v-model. Custom directives encapsulate low-level DOM effects (e.g., autofocus, lazy-load). Prefer components for complex logic.

app.directive('focus', { mounted(el){ el.focus(); } })

8) Lifecycle Hooks

Key Composition hooks: onMounted, onUpdated, onUnmounted, onBeforeRouteLeave (router). Avoid async race conditions by canceling work on unmount.

onMounted(() => fetchData()); onUnmounted(() => abortCtl.abort());

9) Slots & Provide/Inject

Slots compose content; scoped slots pass data down. Use provide/inject for deep dependency passing (theme, i18n), but keep it limited for clarity.

<slot name="footer" :count="items.length"></slot>
provide('theme', ref('light'))

10) Q&A — “When to use watch vs computed?”

Answer: Use computed for pure derivations used in templates or other code; use watch for side effects (fetching, logging, imperative DOM). If you’re assigning to state based on other state, try computed first.

Section 2 — Composition API, Patterns & Reuse

11) Composables (useX)

Extract reusable logic into composable functions that return reactive state, methods, and computed values. Share across components without inheritance.

// useFetch.ts
export function useFetch(url){
  const data = ref(null), error = ref(null), loading = ref(false);
  const run = async() => { loading.value=true; try{ data.value=await (await fetch(url)).json() } catch(e){ error.value=e } finally{ loading.value=false } };
  onMounted(run); return { data, error, loading, run };
}

12) Script Setup Essentials

<script setup> runs once per SFC and auto-exposes top-level bindings to the template. Use defineProps/defineEmits, defineExpose, and withDefaults for ergonomics.

<script setup lang="ts">
interface P{ size?:'sm'|'md'|'lg' }
const props = withDefaults(defineProps<P>(), { size:'md' })
defineExpose({ focus: () => input.value?.focus() })
</script>

13) Refs vs Reactive

Prefer ref for primitives and reactive for objects. When destructuring reactive, use toRefs() to keep reactivity.

const state = reactive({ a:1, b:2 }); const { a, b } = toRefs(state);

14) v-model on Components

Support two-way binding by accepting modelValue and emitting update:modelValue. You can have multiple models with arguments.

<Child v-model="open" /> <!-- maps to modelValue -->
<Child v-model:title="title" v-model:count="n" />

15) Teleport & Suspense

Teleport renders children elsewhere in the DOM (modals/portals). Suspense coordinates async components and fallbacks.

<teleport to="body"><Modal v-if="open" /></teleport>
<Suspense><AsyncChart /><template #fallback>Loading…</template></Suspense>

16) Transitions

Animate enter/leave with the <transition> component. Works with CSS classes or JS hooks; great for modal fades, list moves.

<transition name="fade"><div v-if="show">Hi</div></transition>
<style>.fade-enter-active,.fade-leave-active{transition:opacity .2s}.fade-enter-from,.fade-leave-to{opacity:0}</style>

17) Error Handling

Use errorCaptured to catch child errors and provide fallbacks. For global errors, wrap app-level try/catch and log.

onErrorCaptured((err, inst, info) => { console.error(info, err); return false })

18) Performance Patterns

Prefer computed over watch, use v-memo/keep-alive for caching, and avoid large reactive objects; split stores and lazy routes.

<keep-alive include="UserList"><router-view /></keep-alive>

19) Accessibility

Manage focus on route changes, use semantic tags, ARIA roles for custom widgets, and keyboard shortcuts. Teleport modals should trap focus.

onMounted(() => document.getElementById('main')?.focus())

20) Q&A — “When to create a composable vs component?”

Answer: If the reuse is logic-only (fetching, timers, state), use a composable. If you need UI + logic reusable together, use a component. Combine both by using composables inside components.

Section 3 — Routing, State Management & Data

21) Vue Router Basics

Define routes, nested routes, and dynamic params. Use router.push for navigation and navigation guards for auth.

const router = createRouter({
  history: createWebHistory(),
  routes:[ { path:'/', component:Home }, { path:'/user/:id', component:User } ]
});

22) Route Guards

Global (beforeEach), per-route (beforeEnter), and in-component guards (onBeforeRouteLeave). Check auth, preload data, or cancel navigation.

router.beforeEach((to,from,next)=> auth() ? next() : next('/login'))

23) Pinia Overview

Pinia is the official store for Vue. It’s modular (per-store), type-friendly, and works with Composition API. Use actions for async and getters for derived state.

export const useCart = defineStore('cart',{
  state:()=>({ items:[] }),
  actions:{ add(p){ this.items.push(p) } },
  getters:{ total:(s)=> s.items.length }
})

24) Pinia + Persist

Persist stores with plugins (e.g., localStorage). Selectively persist keys and version data for migrations.

pinia.use(({ store }) => { store.$subscribe((_m, state)=> localStorage.setItem(store.$id, JSON.stringify(state))) })

25) Server Cache vs Client State

Server cache (e.g., fetching layer) stores remote data with lifetimes (stale-while-revalidate). Client state holds UI state and business rules. Don’t mix them.

// Keep filters/sort in Pinia; keep fetched lists in query cache

26) Fetching Patterns

Use onMounted for initial loads, abort controllers on unmount, and exponential backoff. For SSR, fetch in route or page setup and serialize data.

const ctl = new AbortController();
onUnmounted(() => ctl.abort())

27) Forms & v-model

Use v-model for inputs, modifiers (.trim, .number) for parsing, and custom components with modelValue. Validate with Vuelidate or custom composables.

<input v-model.trim="email" type="email" />

28) Internationalization (i18n)

Vue I18n provides messages, pluralization, and lazy-loaded locales. Avoid recomputing on every render by memoizing formatters.

{{ $t('hello_user', { name }) }}

29) Accessibility Routing

Focus the main region on route change, keep landmarks, and announce route changes via ARIA live regions for screen readers.

<div id="main" tabindex="-1" aria-live="polite"><router-view /></div>

30) Q&A — “Pinia vs Vuex?”

Answer: Pinia is the modern successor: simpler API, first-class TS support, modular stores, no mutation boilerplate. Use Pinia unless you maintain legacy Vuex codebases.

Section 4 — Tooling, SSR, Build & Testing

31) Vite Tooling

Vite gives instant dev server via ES modules and fast HMR. Configure aliases, env vars (import.meta.env), and code-splitting by route.

npm create vite@latest myapp -- --template vue-ts

32) TypeScript with Vue

Use vue-tsc for SFC type-checking. Prefer <script setup lang="ts"> for clean inference and IDE hints.

npm i -D vue-tsc; npx vue-tsc --noEmit

33) Build Optimization

Code split by route, prefetch critical chunks, and treeshake unused components. Analyze bundles to spot heavy deps.

npm i -D rollup-plugin-visualizer

34) SSR / SSG Concepts

Server-side render initial HTML for speed/SEO, then hydrate on client. For content sites, use SSG to pre-generate pages at build time.

// Nuxt/Nitro or custom SSR with @vue/server-renderer

35) Nuxt Overview

Nuxt is a meta-framework for Vue: file-based routing, server/data fetching, SSR/SSG, and conventions for SEO and performance.

// pages/index.vue, server/api/*.ts for endpoints

36) Testing: Unit

Use Vitest/Jest + Vue Test Utils for component tests. Mount components with props, simulate events, assert DOM output.

import { mount } from '@vue/test-utils'
expect(mount(Counter).text()).toContain('0')

37) Testing: E2E

Playwright/Cypress for end-to-end tests. Seed fixture data, test routing, forms, and accessibility.

// cy.visit('/'); cy.findByRole('button', {name:/save/i}).click()

38) Linting & Formatting

ESLint + @vue/eslint-config, Prettier for consistent style. Enforce defineProps types and component naming rules.

npm i -D eslint @vue/eslint-config-typescript prettier

39) CI/CD

Run type checks, unit/E2E tests, and build previews on every PR. Cache node_modules and Vite cache for speed.

# GitHub Actions: setup-node, cache, npm ci, npm run build, npm test

40) Q&A — “When pick Nuxt over Vite-only?”

Answer: Choose Nuxt if you need SSR/SSG, file-based routing, server APIs, and SEO out-of-the-box. Use Vite-only for SPAs or when you want minimal scaffolding and full control.

Section 5 — Recipes, Pitfalls & Interview Q&A

41) Recipe: Fetch + Cache Composable

A simple stale-while-revalidate approach: return cached data immediately, then refresh in background and notify dependents.

const cache = reactive(new Map());
export function useCache(key, loader){
  const data = ref(cache.get(key)); const loading = ref(!data.value);
  const refresh = async() => { loading.value=true; const v = await loader(); cache.set(key, v); data.value=v; loading.value=false; };
  onMounted(refresh); return { data, loading, refresh };
}

42) Recipe: Debounced Input

Debounce queries to reduce chatter; cancel stale requests on new input.

const q = ref(''); watch(q, debounce(runSearch, 300));

43) Recipe: Modal with Teleport

Portal modal to body, trap focus, and restore on close.

<teleport to="body"><Modal v-if="open" @close="open=false" /></teleport>

44) Recipe: Infinite List

Use IntersectionObserver composable to fetch next page and append items; show skeletons while loading.

const loadMore = async()=>{ page.value++; items.value.push(...await api(page.value)) }

45) Common Pitfalls

Mutating props, deep reactive structures causing perf issues, forgetting .value on refs, heavy watchers, and global CSS leakage. Fix with computed, shallowRef/shallowReactive, and scoped CSS.

// Don't mutate props; emit updates instead

46) Security Basics

Sanitize user HTML, prefer server-side session cookies, protect API keys, and validate data before rendering. Vue escapes by default—avoid v-html unless sanitized.

<div v-html="safeHtml"></div> <!-- safeHtml must be sanitized -->

47) Accessibility Checklist

Labels for inputs, keyboard nav, focus styles, high contrast, and ARIA roles for composites (tabs, dialog). Test with screen reader + keyboard only.

<button aria-expanded="open" :aria-controls="id">Toggle</button>

48) Production Checklist

Type-check, lint, test, analyze bundle, enable gzip/brotli, configure caching headers, handle errors/logging, and monitor Web Vitals.

import.meta.env.PROD // feature flags per env

49) Migration Tips (Vue 2 → 3)

Use the migration build, replace filters with computed/methods, move to Composition API gradually, update plugins to Vue 3 equivalents, and retest directives.

// Vue 2 filters → Vue 3 computed/formatters

50) Interview Q&A — 20 Practical Questions (Expanded)

1) Options vs Composition API? Options organizes by option type (data, methods); Composition organizes by feature logic via composables—better for scaling and TS.

2) When computed over watch? Use computed for pure derivations; watch for side effects or async flows.

3) Props down, events up? Parents pass props; children emit events back. For deep trees, consider provide/inject or a store (Pinia).

4) What does <script setup> do? Syntactic sugar for Composition API with better treeshaking and less boilerplate; top-level bindings are template-available.

5) How v-model works on components? It maps to modelValue prop and update:modelValue event; supports multiple arguments (e.g., v-model:title).

6) Key differences Vue vs React? Vue uses templates with reactivity system and directives; React uses JSX and a different state model. Vue’s reactivity is automatic; React relies on state setters and reconciliation.

7) Why Pinia over Vuex? Simpler API, no mutations, first-class TS, modular stores; official recommendation for Vue 3.

8) Teleport use cases? Modals, tooltips, dropdowns that must escape overflow/stacking context.

9) Preventing unnecessary updates? Use computed, shallowRef for large objects, v-memo hints, and avoid creating new objects in templates.

10) SSR benefits? Faster first paint, SEO, and predictable content. Requires hydration and careful side-effect handling.

11) How to type props/emits? Use TS generics with defineProps<T> and defineEmits<{ (e:'save', id:number):void }>().

12) Watch vs watchEffect? watch tracks explicit sources; watchEffect tracks dependencies automatically (good for quick reactive effects).

13) Handling async in setup? Run in hooks (onMounted) or use async setup with Suspense; cancel on unmount.

14) Global state options? Pinia for app state; provide/inject for simple shared deps; avoid event buses for complex apps.

15) What is reactive caveat? Destructuring reactive objects breaks reactivity—use toRefs() or keep as object.

16) Optimize lists? Always use stable :key, virtualize long lists, and avoid heavy work in item components.

17) Handling forms? v-model with modifiers, validation composables, and debounced submits; keep source of truth in component or store by need.

18) Error boundaries? Use errorCaptured in parent; provide fallback UI and logging. For global, app-level handlers.

19) Security with v-html? Vue escapes by default; v-html does not—sanitize and trust only safe sources.

20) When to choose Nuxt? For SSR/SSG, SEO, conventions, server API integration, and DX with file-based routing. Otherwise Vite SPA is fine.