Vue 3 mit der Composition API, Pinia-Statusverwaltung und Nuxt.js fรผr Full-Stack โ Vue ist das zweitbeliebteste JavaScript-Framework im Jahr 2026 mit einem hervorragenden Entwicklererlebnis. Dieser vollstรคndige Leitfaden behandelt die Kompositions-API, das Reaktivitรคtssystem und die Produktionsmuster von Vue 3.
๐ Table of Contents
Aufstellen
# Create new project
npm create vue@latest my-app
# Choose: TypeScript, Vue Router, Pinia, ESLint, Prettier
cd my-app && npm install && npm run dev
Kompositions-API
<!-- Counter.vue โ script setup syntax (preferred) -->
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
// ref โ reactive primitive
const count = ref(0);
const name = ref('World');
// computed โ derived state (cached)
const doubled = computed(() => count.value * 2);
const greeting = computed(() => `Hello, ${name.value}! Count: ${count.value}`);
// watch โ side effects
watch(count, (newVal, oldVal) => {
console.log(`Count changed: ${oldVal} โ ${newVal}`);
document.title = `Count: ${newVal}`;
});
// watchEffect โ auto-tracks dependencies
watchEffect(() => {
localStorage.setItem('count', count.value.toString());
});
// Lifecycle hooks
onMounted(() => {
console.log('Component mounted!');
count.value = parseInt(localStorage.getItem('count') || '0');
});
function increment() {
count.value++;
}
function reset() {
count.value = 0;
}
</script>
<template>
<div class="counter">
<h2>{{ greeting }}</h2>
<p>Doubled: {{ doubled }}</p>
<!-- v-model works with refs automatically -->
<input v-model="name" placeholder="Your name" />
<div>
<button @click="increment">+1</button>
<button @click="reset">Reset</button>
</div>
</div>
</template>
Reaktive Objekte mit reactive()
<script setup lang="ts">
import { reactive, toRefs } from 'vue';
// reactive โ for objects (no .value needed)
const state = reactive({
count: 0,
name: 'Alice',
todos: [] as string[],
});
// Destructure with toRefs (maintains reactivity)
const { count, name } = toRefs(state);
// Mutate directly
function addTodo(text: string) {
state.todos.push(text);
}
</script>
Komponenten und Requisiten
<!-- UserCard.vue -->
<script setup lang="ts">
interface Props {
user: {
id: number;
name: string;
email: string;
avatarUrl?: string;
};
isSelected?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isSelected: false,
});
const emit = defineEmits<{
select: [userId: number];
delete: [userId: number];
}>();
function handleSelect() {
emit('select', props.user.id);
}
</script>
<template>
<div
class="user-card"
:class="{ 'user-card--selected': isSelected }"
@click="handleSelect"
>
<img
v-if="user.avatarUrl"
:src="user.avatarUrl"
:alt="user.name"
/>
<div>
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</div>
<button @click.stop="emit('delete', user.id)">Delete</button>
</div>
</template>
Composables โ Benutzerdefinierte Hooks
// composables/useUsers.ts
import { ref, computed } from 'vue';
interface User { id: number; name: string; email: string; }
export function useUsers() {
const users = ref<User[]>([]);
const loading = ref(false);
const error = ref<string | null>(null);
const searchQuery = ref('');
const filteredUsers = computed(() =>
users.value.filter(u =>
u.name.toLowerCase().includes(searchQuery.value.toLowerCase())
)
);
async function fetchUsers() {
loading.value = true;
error.value = null;
try {
const response = await fetch('/api/users');
users.value = await response.json();
} catch (e) {
error.value = 'Failed to load users';
} finally {
loading.value = false;
}
}
async function createUser(data: Omit<User, 'id'>) {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(data),
headers: { 'Content-Type': 'application/json' },
});
const newUser = await response.json();
users.value = [...users.value, newUser];
}
return { users, loading, error, searchQuery, filteredUsers, fetchUsers, createUser };
}
// Usage in component
const { users, loading, error, searchQuery, filteredUsers, fetchUsers } = useUsers();
onMounted(fetchUsers);
Pinia-Staatsverwaltung
// stores/userStore.ts
import { defineStore } from 'pinia';
export const useUserStore = defineStore('users', {
state: () => ({
users: [] as User[],
currentUser: null as User | null,
loading: false,
}),
getters: {
activeUsers: (state) => state.users.filter(u => u.active),
userCount: (state) => state.users.length,
},
actions: {
async fetchUsers() {
this.loading = true;
try {
this.users = await api.getUsers();
} finally {
this.loading = false;
}
},
async createUser(data: CreateUserInput) {
const user = await api.createUser(data);
this.users.push(user);
return user;
},
logout() {
this.currentUser = null;
}
}
});
// In component
import { useUserStore } from '@/stores/userStore';
const store = useUserStore();
await store.fetchUsers();
console.log(store.userCount);
store.logout();
Vue vs. React: Wann Sie sich fรผr Vue entscheiden sollten
- Wรคhlen Sie Vue wann: Einfachere Lernkurve erforderlich, Template-First-Ansatz bevorzugt, kleineres Team, schrittweise Migration von jQuery/Vanilla JS
- Wรคhlen Sie Reagieren, wenn: Groรes Team, komplexes Zustandsmanagement erforderlich, Next.js-รkosystem, React Native fรผr Mobilgerรคte
- Beide sind ausgezeichnetBei den meisten Web-Apps hรคngt die Wahl oft von der Vertrautheit des Teams ab
Vue 3 im Jahr 2026 mit Skript-Setup, Composition API und Pinia ist ein ausgereiftes, entwicklerfreundliches Framework. Die Vorlagensyntax ist fรผr viele Entwickler zugรคnglicher als JSX und die Composition API bietet volle Leistung fรผr komplexe Komponenten. Fรผr den Full-Stack kombinieren Sie es mit Nuxt.js, um die gleichen Produktivitรคtssteigerungen wie Next.js fรผr React zu erzielen.
๐ Share this article
โ๏ธ Leave a Comment