Tavaly szeptemberi megjelenésével a Vue 3 több, mint 2 évnyi munka eredményeként rengeteg újdonságot hozott: jobb performancia, kisebb méret, jobb TypeScript integráció, új API-k nagyobb projektekhez és egy stabil alap a keretrendszer jövőbeni fejlesztéséhez.
A következőkben a Composition API működését fogom bemutatni egy egyszerű todo alkalmazás példáján keresztül.
A Vue egyre szélesebb körű terjedésével növekszik azon fejlesztők száma is, akik nagy projektekhez használják: olyan projektekhez, amiket hosszú időn keresztül több fejlesztőből álló csapatok fejlesztenek és tartanak karban. Az évek során a Vue készítői felismerték, hogy az ilyen projektek egy része limitációkba ütközik a 2-es verzió objektum alapú API-jával felállított programozási modell miatt. Ezek a problémák két kategóriába sorolhatók:
A Composition API ezekre a problémákra nyújt megoldást a komponensek kódjának rugalmasabb szervezésével. Az opciókba kényszerített szervezés helyett immáron adott a lehetőség, hogy az önálló funkciók önálló függvényekbe kerüljenek és sokkal könnyebbé tették a logika újrahasznosítását különböző komponensek között vagy akár komponenseken kívül is.
A fejlesztés során a Vite csomagot fogjuk használni fejlesztői környezetként, amit Evan You (a Vue.js készítője) és társai készítettek. Ez egy villámgyors eszköz, amivel mind a fejlesztés, mind a buildek készítése másodpercek töredéke alatt megtörténik. A mi egyszerű todo alkalmazásunk fejlesztésekor fel se fog tűnni, hogy a háttérben a kód lefordul és automatikusan frissül a böngészőben látott verzió is.
Követelmények: Node.js 12 vagy újabb verzió
Hozzuk létre tehát az alkalmazásunkat:
# npm 6.x esetén
npm init @vitejs/app todo --template vue
# npm 7+ esetén szükséges egy extra dupla kötőjel
npm init @vitejs/app todo -- --template vue
A létrehozást követően lépjünk be a mappába, telepítsük a csomagokat, majd indítsuk el:
cd todo
npm install
npm run dev
Az alkalmazást ezután a http://localhost:3000/ címen érjük el.
A minta HelloWorld
komponens törlését követően lássunk neki a munkához.
Az egyszerűség kedvéért most egyetlen komponensben fogunk dolgozni, de egy való életbeli alkalmazás esetén ügyeljünk a komponensek és felelősségek különválasztására. Szükségünk lesz egy tömbre, amiben a teendőket tároljuk, illetve egy inputra, ahol azokat felvihetjük.
Hozzuk létre a src/components/TodoList.vue
fájlt, ahol egy inputba megadhatjuk a következő teendőt:
<template>
<input type="text" v-model="todo" placeholder="Teendő">
{{ todo }}
</template>
<script>
export default {
setup () {
const todo = ''
return {
todo
}
}
}
</script>
See the Pen jOMzGbj by Szabolcs Légrádi (@szlegradi) on CodePen.
A CodePen példákban a Vue CDN-en elérhető verziója van betöltve, ahol minden függvény a
Vue
névtér alatt található.
A setup
függvény szolgál a kompozíciós függvények helyéül. Itt definiálhatjuk a változókat, metódusokat és a kalkulált (computed
) mezőket, amik a komponensünk számára elérhetőek lesznek. Láthatjuk, hogy bár a templateben megjelenítjük a todo
értékét és az input elemünkön is szerepel a v-model
, a beírt érték mégse frissül.
Ennek oka, hogy a todo
változó nem reaktív, így változás esetén nem frissül a DOM.
Tegyük hát reaktívvá a ref
függvény segítségével.
A ref
a Reactive Reference, vagyis reaktív referencia rövidítése, nem csinál mást, mint a paraméterben átadott értéket egy objektumba csomagolja, aminek lesz egy value
mezője.
<template>
<input type="text" v-model="todo" placeholder="Teendő">
<p>{{ todo }}</p>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const todo = ref('')
return {
todo
}
}
}
</script>
See the Pen Vue 3 Composition API - TodoList reaktív input by Szabolcs Légrádi (@szlegradi) on CodePen.
Máris látható, hogy működik a DOM és a model közötti szinkron! Fontos, hogy render kontextusban (ez a setup
függvény által visszaadott objektum) a ref
kicsomagolására nincs szükség (vagyis nem kell todo.value
-ként hivatkoznunk rá), ez automatikusan megtörténik.
Következő lépésként listázzuk a teendőinket: ehhez létrehozunk egy tömböt, amiben tárolni fogjuk őket. Minden teendőnek lesz egy címe, illetve egy completed
mezője, ami jelzi, hogy az adott feladat el lett-e már végezve vagy sem.
<template>
<input type="text" v-model="todo" placeholder="Teendő" @keyup.enter="addTodo">
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.completed">
{{ todo.title }}
</li>
</ul>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const todo = ref('')
const todos = ref([])
let id = 0
function addTodo () {
todos.value.push({
id: id,
title: todo.value.trim(),
completed: false
})
todo.value = ''
id++
}
return {
todo,
todos,
addTodo
}
}
}
</script>
See the Pen Vue 3 Composition API - TodoList teendők listázása by Szabolcs Légrádi (@szlegradi) on CodePen.
Látható, hogy a setup
függvényen belül az adott változó value
mezőjére kell hivatkoznunk, azon keresztül érjük el az adott típusra vonatkozó metódusokat. Az új teendő hozzáadását követően a DOM azonnal frissül és megjelenik a legutóbb hozzáadott feladat.
Tegyük fel, hogy kíváncsiak vagyunk a teendők számára minden alkalommal, amikor egy új teendőt felveszünk és ezt a konzolra ki akarjuk íratni. Ezt a watch
függvénnyel tudjuk megtenni, ami 3 paramétert fogad:
<template>
<input type="text" v-model="todo" placeholder="Teendő" @keyup.enter="addTodo">
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.completed">
{{ todo.title }}
</li>
</ul>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup () {
const todo = ref('')
const todos = ref([])
let id = 0
function addTodo () {
todos.value.push({
id: id,
title: todo.value.trim(),
completed: false
})
todo.value = ''
id++
}
watch(todos, (newValue, oldValue) => {
console.log(`A teendők új száma: ${newValue.length}`)
}, { deep: true })
return {
todo,
todos,
addTodo
}
}
}
</script>
See the Pen Vue 3 Composition API - TodoList reagálás a változásokra by Szabolcs Légrádi (@szlegradi) on CodePen.
A konzolt megnyitva láthatjuk, hogy a teendők hozzáadásakor naplózásra kerül azok száma. Mivel tömböt vizsgálunk, ezért a deep: true
beállítást is átadtuk a függvénynek, máskülönben csak akkor értesülnénk a változásokról, ha a todos
változóra való referencia megváltozna. Primitív értékek esetén (mint számok vagy stringek) a deep
beállításra nincs szükség.
computed
mezőkHasonlóan a ref
és watch
függvényekhez, kalkulált mezőket is létrehozhatunk a computed
függvénnyel. Készítsünk egyet, amivel az elkészült feladatok számát tudjuk megjeleníteni a felületen.
<template>
<input type="text" v-model="todo" placeholder="Teendő" @keyup.enter="addTodo">
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.completed">
{{ todo.title }}
</li>
</ul>
<p>Elkészült feladatok száma: {{ numberOfCompletedTodos }}</p>
</template>
<script>
import { computed, ref, watch } from 'vue'
export default {
setup () {
const todo = ref('')
const todos = ref([])
let id = 0
const numberOfCompletedTodos = computed(() =>
todos.value.filter(todo => todo.completed).length
)
function addTodo () {
todos.value.push({
id: id,
title: todo.value.trim(),
completed: false
})
todo.value = ''
id++
}
watch(todos, (newValue, oldValue) => {
console.log(`A teendők új száma: ${newValue.length}`)
}, { deep: true })
return {
todo,
todos,
addTodo,
numberOfCompletedTodos
}
}
}
</script>
See the Pen Vue 3 Composition API - TodoList computed mezők by Szabolcs Légrádi (@szlegradi) on CodePen.
Egy-egy feladat elvégzését követően láthatjuk az elkészült feladatok számát frissülni.
Ezzel készen is vagyunk!
Izgalmas lesz látni, hogy miként alakulnak át a nagyobb kódbázisok a közeljövőben és milyen Composition API alapú megoldásokkal fog előrukkolni a fejlesztői közösség.
A cikkben csak a felszínt kapargattuk, ha felkeltette az érdeklődésed és szeretnél még többet megtudni róla, akkor javaslom a dokumentáció tanulmányozását, illetve a már erre épülő megoldásokat, mint például a VueUse, ami egy szép gyűjteménye alapvető utility függvényeknek.
A cikkben elkészített projekt megtalálható GitHub-on és CodePen-en .