Frontend'de durum yönetimi: Pinia ile Vuex sonrası
Vue ekosisteminde Pinia'nın Vuex'in yerini alması: daha az şablon kod, daha iyi TypeScript desteği ve olgunlaşan durum yönetimi anlayışı.
Vue ekosisteminde durum yönetimi uzun süre Vuex’in tekelindeydi. Vuex işe yarıyordu; ama Vue 3 ve Composition API ile birlikte bazı kırışıklıklar daha görünür hale geldi. Boilerplate fazlaydı, TypeScript desteği sonradan eklenmişti ve store’u mutation-action-getter üçlüsüyle organize etmek kimi zaman basit bir sorunu karmaşık hale getiriyordu.
Pinia, Vuex’in resmi halefi olarak Vue’nun kendi ekibinden çıktı. Vue 3 için tasarlandı, Composition API ile uyumlu ve TypeScript desteği sıfırdan geldi. Vue 5 ile birlikte Vuex tamamen kaldırılacak; Pinia şu an resmi olarak önerilen yol.
Pinia ile store yazmak
Pinia’nın en belirgin farkı, store tanımının ne kadar sade olduğu. Vuex’teki state/mutations/actions/getters dörtlüsü yerine tek bir defineStore çağrısı:
// stores/cart.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCartStore = defineStore('cart', () => {
const items = ref([])
const totalPrice = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
function addItem(product) {
const existing = items.value.find(i => i.id === product.id)
if (existing) {
existing.quantity++
} else {
items.value.push({ ...product, quantity: 1 })
}
}
function removeItem(productId) {
items.value = items.value.filter(i => i.id !== productId)
}
return { items, totalPrice, addItem, removeItem }
})
Bu, Composition API’nin setup fonksiyonu gibi yazılmış bir store. ref ve computed zaten bildiğiniz şeyler; ayrı bir API öğrenmenize gerek yok.
Bileşende kullanmak:
import { useCartStore } from '@/stores/cart'
const cart = useCartStore()
// Doğrudan erişim
console.log(cart.totalPrice)
cart.addItem(product)
Vuex ile karşılaştırma
Vuex’te aynı işlemi yapmak için en az dört katman gerektirirdi: state tanımı, mutation yazımı, action yazımı, getter tanımı. Sonra component’te mapState, mapActions, mapGetters ile bağlama.
Pinia bunu üçe indiriyor: state (ref), computed, fonksiyon. Ve bunlar zaten Vue Composition API’nin standart yapıtaşları.
TypeScript desteği açısından Vuex, $store.state.cart.items gibi erişimlerde tip çıkarımı yapamıyordu; manuel tanımlamalar gerekiyordu. Pinia’da store’unuzu defineStore ile tanımladığınız anda, her şeyin tipi otomatik çıkarılıyor. useCartStore() döndürülen nesne tam tiplenmiş.
Birden fazla store
Vuex’te modüller arası erişim bazen kafa karıştırıcı olabilirdi: this.$store.dispatch('auth/logout') gibi string tabanlı referanslar. Pinia’da store’lar birbirinden bağımsız; birinin içinde diğerini kullanmak istiyorsanız doğrudan import ediyorsunuz.
// stores/order.js
import { useCartStore } from './cart'
import { useAuthStore } from './auth'
export const useOrderStore = defineStore('order', () => {
async function placeOrder() {
const cart = useCartStore()
const auth = useAuthStore()
// cart.items ve auth.user doğrudan erişilebilir
// ...
}
return { placeOrder }
})
String referans yok, modül hiyerarşisi yok, düz JavaScript.
$reset() ve store sıfırlama
Vuex’te yoklayan bir özellik, Pinia’da seçeneğe sunuluyor: $reset(). Options API stiliyle yazılmış store’larda state’i başlangıç değerine döndürmek için kullanılıyor. Oturum kapatmada tüm store’ları sıfırlamak ya da bir form wizard’ın adımları arasında temizlik yapmak için işe yarıyor.
Setup stili (yukarıda gösterdiğim () => {} biçimi) kullandığınızda $reset() varsayılan olarak gelmiyor; kendi sıfırlama fonksiyonunuzu yazmanız gerekiyor. Bu küçük bir ödünleşim — setup stilinin esnekliğine karşılık otomatik $reset() kolaylığından vazgeçiyorsunuz.
Ne zaman durum yönetimine ihtiyaç duyulmaz
Pinia ne kadar sade olursa olsun, durum yönetimi her problem için doğru araç değil. Eğer veriyi yalnızca bir bileşen kullanıyorsa, o bileşenin kendi ref’leri yeterli. Veri iki bileşen arasında paylaşılıyorsa, props ve emit döngüsü genellikle daha temiz.
Store’u en fazla şu durumda kullanmak mantıklı: verinin birden fazla, birbiriyle doğrudan ilişkisi olmayan bileşen tarafından okunması veya değiştirilmesi gerektiğinde. Alışveriş sepeti, kimlik doğrulama durumu, global bildirimler — bunlar iyi örnekler. Bir sayfa bileşeninin form durumu — muhtemelen değil.
Pinia ile nerede duruyorum
Pinia’ya geçiş, Vue 3 ile geliştiricilerin en az dirençle yaşadığı değişikliklerden biri oldu. Öğrenme eğrisi neredeyse sıfır; Composition API biliyorsanız, Pinia’yı ilk bakışta anlıyorsunuz. Boilerplate azalması ciddi; özellikle orta büyüklükteki store’larda fark belirgin.
Vue ekosistemine bakışın olgunlaşmasını görmek güzel. Vuex yanlış değildi; kendi döneminin doğru çözümüydü. Pinia, Vue’nun şimdiki felsefesine daha uygun oturuyor.