belajarkoding © 2025 BelajarKoding. All rights reserved.
Vue 3 Cheat Sheet - BelajarKoding | BelajarKoding
Vue 3 Cheat Sheet Referensi lengkap Vue 3 dengan Composition API. Reactive state, lifecycle, components, dan fitur modern Vue. Perfect buat frontend development.
JavaScript 11 min read 2.023 kataLanjutkan Membaca
Daftar gratis untuk akses penuh ke semua artikel dan cheat sheet. Cepat, mudah, dan tanpa biaya!
Akses Tanpa Batas
Baca semua artikel dan cheat sheet kapan pun kamu mau
Bookmark Konten
Simpan artikel dan roadmap favoritmu untuk dibaca nanti
Gratis Selamanya
Tidak ada biaya tersembunyi, 100% gratis
Dengan mendaftar, kamu setuju dengan syarat dan ketentuan kami
# Getting Started
Panduan awal untuk memulai pengembangan aplikasi dengan Vue.js framework.
# Installation
Cara menginstall Vue.js menggunakan berbagai method seperti npm atau CDN.
# Pake npm
npm create vue@latest
# Pake pnpm
pnpm create vue@latest
# Via CDN
< script src = "https://unpkg.com/vue@3" >< /script >
# Basic App
Cara membuat aplikasi Vue.js dasar dengan setup minimal.
import { createApp } from 'vue'
import App from './App.vue'
createApp (App). mount ( '#app' )
# Template Syntax
Sintaks template Vue.js untuk menampilkan data dan mengatur interaksi.
# Text Interpolation
Cara menampilkan data JavaScript dalam template menggunakan double curly braces.
< template >
< p >{{ message }}</ p >
< p >{{ count + 1 }}</ p >
< p >{{ ok ? 'YES' : 'NO' }}</ p >
< p >{{ message. split
# Directives
Directive Vue.js untuk mengatur behavior element HTML dengan berbagai fungsi.
< template >
<!-- v-bind - Attribute binding -->
< img v-bind : src = " imageUrl " />
<
# Composition API
API baru Vue 3 untuk mengorganisir logic komponen dengan cara yang lebih fleksibel.
# setup() Function
Fungsi setup yang menjadi entry point untuk Composition API dalam komponen.
< script >
import { ref, reactive } from 'vue'
export default {
setup () {
const count = ref ( 0 )
const user = reactive ({
name: 'Budi'
# script setup (Recommended)
Sintaks script setup yang lebih sederhana untuk menggunakan Composition API.
< script setup >
import { ref, reactive } from 'vue'
// Gak perlu return, auto-exposed ke template
const count = ref ( 0 )
const user = reactive ({
name: 'Budi' ,
age:
# Reactivity
Sistem reaktivitas Vue.js yang secara otomatis mengupdate UI ketika data berubah.
# ref
Cara membuat reactive reference untuk primitive values.
< script setup >
import { ref } from 'vue'
// Reactive reference
const count = ref ( 0 )
const message = ref ( 'Hello' )
// Access value dengan .value
console.
# reactive
< script setup >
import { reactive } from 'vue'
// Reactive object
const state = reactive ({
count: 0 ,
message: 'Hello'
})
// Akses langsung, gak pake .value
state.count
# computed
< script setup >
import { ref, computed } from 'vue'
const firstName = ref ( 'Budi' )
const lastName = ref ( 'Santoso' )
// Computed property
# watch & watchEffect
< script setup >
import { ref, watch, watchEffect } from 'vue'
const count = ref ( 0 )
const user = reactive
# Lifecycle Hooks
# Composition API Lifecycle
< script setup >
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// Before component is mounted
onBeforeMount
# Components
# Defining Components
<!-- MyComponent.vue -->
< script setup >
import { ref } from 'vue'
const count = ref ( 0 )
</ script >
< template >
< button @ click
# Props
< script setup >
// Define props
const props = defineProps ({
title: String,
count: {
type: Number,
default: 0 ,
required: true
},
user: Object,
tags: Array
# Emits
< script setup >
// Define emits
const emit = defineEmits ([ 'update' , 'delete' ])
// Dengan validation
const emit = defineEmits ({
update : (
# v-model Component
<!-- Parent -->
< template >
< CustomInput v-model = " text " />
</ template >
<!-- CustomInput.vue -->
< script setup >
const props = defineProps
# Slots
<!-- Parent -->
< template >
< Card >
< template # header >
< h1 >Title</ h1 >
</ template >
< template #
# Scoped Slots
<!-- Parent -->
< template >
< UserList >
< template # default = " { user } " >
< p >{{ user.name }} - {{ user.email }}</ p >
</ template >
# Composables
# Creating Composables
// useCounter.js
import { ref, computed } from 'vue'
export function useCounter ( initialValue = 0 ) {
const count = ref (initialValue)
const doubled = computed (() =>
# Using Composables
< script setup >
import { useCounter } from './composables/useCounter'
const { count , doubled , increment , decrement , reset } = useCounter ( 10 )
</
# Common Composables
// useFetch.js
import { ref } from 'vue'
export function useFetch ( url ) {
const data = ref ( null )
const error
# Pinia (State Management)
# Store Setup
// main.js
import { createPinia } from 'pinia'
const pinia = createPinia ()
app. use (pinia)
# Defining Stores
// stores/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore ( 'counter' , () => {
// State
# Using Stores
< script setup >
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore ()
// Access state
console. log (counter.count)
// Access getters
console. log (counter.doubled)
# Router
# Setup
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
const routes = [
{
path: '/' ,
# Using Router
< script setup >
import { useRouter, useRoute } from 'vue-router'
const router = useRouter ()
const route = useRoute ()
// Navigate
function goToAbout
# Directives
# Built-in Directives
< template >
<!-- v-text -->
< span v-text = " message " ></ span >
<!-- v-html (hati-hati XSS!) -->
< div v-html = " htmlContent " ></ div >
# Custom Directives
< script setup >
// Directive definition
const vFocus = {
mounted ( el ) {
el. focus ()
}
}
const vColor = {
mounted ( el
# Teleport
< template >
<!-- Teleport ke body -->
< Teleport to = "body" >
< div class = "modal" >
< p >Modal content</ p >
</ div >
</ Teleport >
# Suspense
< template >
< Suspense >
<!-- Component yang async -->
< template # default >
< AsyncComponent />
</ template >
<!-- Loading state -->
< template # fallback >
# Tips & Best Practices
# Computed vs Methods
< script setup >
import { ref, computed } from 'vue'
const count = ref ( 0 )
// Computed - cached, cuma re-evaluate kalo dependencies berubah
const doubled = computed (() => count.value
# Component Organization
< script setup >
// 1. Imports
import { ref, computed, onMounted } from 'vue'
import MyComponent from './MyComponent.vue'
// 2. Props & Emits
const props = defineProps ([ 'title' ])
const
# Performance
< script setup >
import { shallowRef, shallowReactive } from 'vue'
// Shallow reactivity - cuma top-level yang reactive
const state = shallowReactive ({
foo: 1 ,
nested: {
bar: 2
}
})
# defineOptions (Vue 3.3+)
< script setup >
// Set component options
defineOptions ({
name: 'MyComponent' ,
inheritAttrs: false
})
</ script > (
''
).
reverse
().
join
(
''
) }}</
p
>
</ template >
img
:
src
=
"
imageUrl
"
/>
<!-- Shorthand -->
< div : class = " { active: isActive } " ></ div >
< div : style = " { color: textColor } " ></ div >
<!-- v-on - Event handling -->
< button v-on : click = " handleClick " >Click</ button >
< button @ click = " handleClick " >Click</ button > <!-- Shorthand -->
< input @ input = " handleInput " />
<!-- v-model - Two-way binding -->
< input v-model = " message " />
< textarea v-model = " text " ></ textarea >
< input type = "checkbox" v-model = " checked " />
< select v-model = " selected " >
< option >A</ option >
< option >B</ option >
</ select >
<!-- v-if, v-else-if, v-else -->
< div v-if = " type === 'A'" >A</ div >
< div v-else-if = " type === 'B'" >B</ div >
< div v-else >Not A or B</ div >
<!-- v-show (CSS display) -->
< div v-show = " isVisible " >Show me</ div >
<!-- v-for - List rendering -->
< li v-for = " item in items " : key = " item.id " >
{{ item.name }}
</ li >
< div v-for = " (item, index) in items " : key = " index " >
{{ index }}: {{ item }}
</ div >
< div v-for = " (value, key) in object " : key = " key " >
{{ key }}: {{ value }}
</ div >
</ template >
,
age: 25
})
function increment () {
count.value ++
}
return {
count,
user,
increment
}
}
}
</ script >
25
})
function increment () {
count.value ++
}
</ script >
< template >
< button @ click = " increment " >{{ count }}</ button >
< p >{{ user.name }}</ p >
</ template >
log
(count.value)
// 0
count.value ++
// Di template gak perlu .value
</ script >
< template >
< p >{{ count }}</ p >
</ template >
++
state.message = 'Hi'
// Nested objects juga reactive
const user = reactive ({
profile: {
name: 'Budi' ,
email: 'budi@example.com'
}
})
user.profile.name = 'Ani' // Reactive
</ script >
const fullName = computed (() => {
return firstName.value + ' ' + lastName.value
})
// Writable computed
const fullNameWritable = computed ({
get () {
return firstName.value + ' ' + lastName.value
},
set ( value ) {
[firstName.value, lastName.value] = value. split ( ' ' )
}
})
</ script >
< template >
< p >{{ fullName }}</ p >
</ template >
({ name:
'Budi'
})
// Watch specific source
watch (count, ( newValue , oldValue ) => {
console. log ( `Count changed from ${ oldValue } to ${ newValue }` )
})
// Watch multiple sources
watch ([count, () => user.name], ([ newCount , newName ]) => {
console. log ( `Count: ${ newCount }, Name: ${ newName }` )
})
// Deep watch untuk object
watch (
() => user,
( newUser ) => {
console. log ( 'User changed:' , newUser)
},
{ deep: true }
)
// watchEffect - auto track dependencies
watchEffect (() => {
console. log ( `Count is ${ count . value }` )
})
// watchEffect dengan cleanup
watchEffect (( onCleanup ) => {
const timer = setTimeout (() => {
console. log (count.value)
}, 1000 )
onCleanup (() => {
clearTimeout (timer)
})
})
</ script >
(()
=>
{
console. log ( 'Before Mount' )
})
// After component is mounted
onMounted (() => {
console. log ( 'Mounted' )
// Good place buat API calls, DOM manipulation
})
// Before component updates
onBeforeUpdate (() => {
console. log ( 'Before Update' )
})
// After component updates
onUpdated (() => {
console. log ( 'Updated' )
})
// Before component unmounts
onBeforeUnmount (() => {
console. log ( 'Before Unmount' )
// Cleanup subscriptions, timers, etc
})
// After component unmounts
onUnmounted (() => {
console. log ( 'Unmounted' )
})
</ script >
=
"
count
++
"
>{{ count }}</
button
>
</ template >
< style scoped >
button {
background : blue ;
color : white ;
}
</ style >
})
// Dengan TypeScript
const props = defineProps <{
title : string
count ?: number
user : { name : string ; age : number }
}>()
// Access props
console. log (props.title)
console. log (props.count)
</ script >
< template >
< h1 >{{ title }}</ h1 >
< p >{{ count }}</ p >
</ template >
value
)
=>
{
return typeof value === 'string'
},
delete: null
})
// Dengan TypeScript
const emit = defineEmits <{
update : [ value : string ]
delete : [ id : number ]
}>()
// Emit event
function handleUpdate () {
emit ( 'update' , 'new value' )
}
function handleDelete () {
emit ( 'delete' , 123 )
}
</ script >
< template >
< button @ click = " handleUpdate " >Update</ button >
< button @ click = " handleDelete " >Delete</ button >
</ template >
([
'modelValue'
])
const emit = defineEmits ([ 'update:modelValue' ])
function handleInput ( e ) {
emit ( 'update:modelValue' , e.target.value)
}
</ script >
< template >
< input
: value = " modelValue "
@ input = " handleInput "
/>
</ template >
default
>
< p >Content here</ p >
</ template >
< template # footer >
< button >OK</ button >
</ template >
</ Card >
</ template >
<!-- Card.vue -->
< template >
< div class = "card" >
< div class = "card-header" >
< slot name = "header" ></ slot >
</ div >
< div class = "card-body" >
< slot ></ slot > <!-- Default slot -->
</ div >
< div class = "card-footer" >
< slot name = "footer" ></ slot >
</ div >
</ div >
</ template >
</ UserList >
</ template >
<!-- UserList.vue -->
< script setup >
const users = ref ([
{ id: 1 , name: 'Budi' , email: 'budi@example.com' },
{ id: 2 , name: 'Ani' , email: 'ani@example.com' }
])
</ script >
< template >
< div v-for = " user in users " : key = " user.id " >
< slot : user = " user " ></ slot >
</ div >
</ template >
count.value
*
2
)
function increment () {
count.value ++
}
function decrement () {
count.value --
}
function reset () {
count.value = initialValue
}
return {
count,
doubled,
increment,
decrement,
reset
}
}
script
>
< template >
< p >Count: {{ count }}</ p >
< p >Doubled: {{ doubled }}</ p >
< button @ click = " increment " >+</ button >
< button @ click = " decrement " >-</ button >
< button @ click = " reset " >Reset</ button >
</ template >
=
ref
(
null
)
const loading = ref ( false )
async function fetchData () {
loading.value = true
try {
const response = await fetch (url)
data.value = await response. json ()
} catch (e) {
error.value = e
} finally {
loading.value = false
}
}
return { data, error, loading, fetchData }
}
// useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage ( key , defaultValue ) {
const value = ref (
JSON . parse (localStorage. getItem (key)) ?? defaultValue
)
watch (value, ( newValue ) => {
localStorage. setItem (key, JSON . stringify (newValue))
}, { deep: true })
return value
}
const count = ref ( 0 )
// Getters
const doubled = computed (() => count.value * 2 )
// Actions
function increment () {
count.value ++
}
function decrement () {
count.value --
}
return {
count,
doubled,
increment,
decrement
}
})
// Options API style
export const useCounterStore = defineStore ( 'counter' , {
state : () => ({
count: 0
}),
getters: {
doubled : ( state ) => state.count * 2
},
actions: {
increment () {
this .count ++
}
}
})
// Call actions
counter. increment ()
// Destructure dengan storeToRefs
import { storeToRefs } from 'pinia'
const { count , doubled } = storeToRefs (counter)
const { increment , decrement } = counter
</ script >
name: 'home' ,
component: Home
},
{
path: '/about' ,
name: 'about' ,
component: About
},
{
path: '/user/:id' ,
name: 'user' ,
component : () => import ( '@/views/User.vue' ) // Lazy loading
}
]
const router = createRouter ({
history: createWebHistory (),
routes
})
export default router
() {
router. push ( '/about' )
router. push ({ name: 'about' })
router. push ({ path: '/user/123' })
}
// Access params
console. log (route.params.id)
// Access query
console. log (route.query.search)
</ script >
< template >
<!-- router-link -->
< router-link to = "/" >Home</ router-link >
< router-link : to = " { name: 'about' } " >About</ router-link >
<!-- router-view -->
< router-view />
</ template >
<!-- v-cloak -->
< div v-cloak >{{ message }}</ div >
<!-- v-once - render sekali -->
< span v-once >{{ message }}</ span >
<!-- v-memo - memoize subtree -->
< div v-memo = " [count] " >
{{ count }}
</ div >
</ template >
,
binding
) {
el.style.color = binding.value
},
updated ( el , binding ) {
el.style.color = binding.value
}
}
</ script >
< template >
< input v-focus />
< p v-color = "'red'" >Red text</ p >
</ template >
<!-- Teleport ke selector -->
< Teleport to = "#modal-container" >
< div >Content</ div >
</ Teleport >
</ template >
< div >Loading...</ div >
</ template >
</ Suspense >
</ template >
< script setup >
// AsyncComponent.vue
const data = await fetch ( '/api/data' ). then ( r => r. json ())
</ script >
*
2
)
// Method - always execute
function getDoubled () {
return count.value * 2
}
</ script >
< template >
<!-- Computed - efficient -->
< p >{{ doubled }}</ p >
<!-- Method - execute setiap render -->
< p >{{ getDoubled () }}</ p >
</ template >
emit
=
defineEmits
([
'update'
])
// 3. State
const count = ref ( 0 )
// 4. Computed
const doubled = computed (() => count.value * 2 )
// 5. Functions
function increment () {
count.value ++
}
// 6. Lifecycle
onMounted (() => {
console. log ( 'Mounted' )
})
</ script >
// Bisa update nested tapi gak trigger reactivity
state.nested.bar = 3 // Won't trigger update
// Update top-level bakal trigger
state.foo = 2 // Will trigger
</ script >