Vue.js 3.2: Code sparen in Single File Components

Seite 3: Das Rad nicht neu erfinden – VueUse nutzen

Inhaltsverzeichnis

Ein großer Vorteil der Composition API, und damit auch von <script setup>, ist das Auslagern von Funktionen in Composables. So lassen sich nicht nur der Template-Teil einer Komponente wiederverwenden, sondern auch zum Beispiel ganze Browser-APIs abstrahieren. Die Composables haben das Präfix use und lassen sich eigenständig als npm-Pakete veröffentlichen. Eine umfangreiche Bibliothek solcher Composables ist im VueUse-Projekt zu finden. Sie bietet eine große Auswahl an Funktionen, die bestehende Browser-APIs abkapseln, reaktive Sensorinformationen vom Browser zurückgeben oder das Arbeiten mit Animationen vereinfachen können.

So könnte die Notizen-Komponente mithilfe der localStorage-Browser-API persistente Speicherung erhalten. VueUse ist als npm-Paket verfügbar und lässt sich wie folgt installieren:

npm install @vueuse/core

Danach lässt sich die Notizen-Komponente mit der useLocalStorage-Funktion erweitern.

// MyNote.vue
<script setup>
import { useLocalStorage } from '@vueuse/core'
import MyTextarea from './MyTextarea.vue'

const props = defineProps(['user'])
const emit = defineEmits(['saved'])

const note = useLocalStorage('my-note', '')

function saveNote() {
  // API-Aufruf zum Abspeichern der Notiz
  emit('saved')}
</script>

Aus const note = ref('') entstand mithilfe von VueUse const note = useLocalStorage('my-note', ''). Der Browser speichert den Notizeninhalt nun persistierend unter dem Schlüssel my-note und stellt ihn auch nach einem Browser-Neustart weiterhin zur Verfügung. Ein Blick auf die vorhandenen Funktionen lohnt sich, denn es lässt sich viel Boilerplate-Code und Zeit sparen.

Für Projekte, die bereits TypeScript nutzen, bietet <script setup> zusätzliche Features. So lassen sich die Props in defineProps auch direkt mit TypeScript typisieren. In JavaScript lassen sich Props mit Typisierungscheck folgendermaßen definieren:

const props = defineProps({
 userName: { type: String, required: true,  },
 age: { type: Number, required: false, }}
)

Mit nativer TypeScript-Unterstützung sieht es dann so aus:

const props = defineProps<{
  userName: string
  age?: number
}>()

Hier definieren die generischen TypeScript-Typen zwischen den spitzen Klammern die Props direkt. Wer zusätzlich Default-Werte mitgeben will, kann dabei auf das Compiler-Makro withDefaults zurückgreifen:

const props = withDefaults(
  defineProps<{ age?: number }>(),
  { age: 20 }
)

Ist age undefiniert, kommt stattdessen der Default-Wert 20 zum Einsatz.

Analog zu den Props lassen sich auch emittierte Events typisieren:

const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()

Wer eine Entwicklungsumgebung mit TypeScript-Unterstützung nutzt, etwa Visual Studio Code mit der Erweiterung Volar oder WebStorm, kann sich auf umfassende Autovervollständigung freuen. Das gilt auch für den <template>-Teil einer Vue.js-Komponente.

Wem der Syntactic Sugar von <script setup> nicht ausreicht, kann noch den zusätzlichen Ref Sugar aktivieren. Er befindet sich allerdings noch in der RFC-Phase und ist daher mit Vorsicht zu genießen. Er ermöglicht das Schreiben folgenden Codes:

let count = $ref(1)

console.log(count) // 1

function inc() {
  count++
}

$ref() ist ein Compiler-Makro, das bei jedem Auftreten der Variable count ein .value anhängt. In der klassischen Composition API müssten das Entwicklerinnen und Entwickler selbst übernehmen. Der kompilierte Code sieht folgendermaßen aus:

import { ref } from 'vue'

const count = ref(1)

console.log(count.value)

function inc() {
  count.value++
}

Wer die Features schon ausprobieren möchte, muss dazu die vite.config.js-Datei anpassen:

export default {
  plugins: [
    vue({ refTransform: true })
  ]
}

Weitere Informationen sowie Anleitungen, wie Nutzer des Vue-CLI oder eines anderen Build-Systems das Feature einschalten können, finden sich im RFC von Vue.js-Ersteller Evan You.