#vueogreniyoruz: Vuex kullanımı

Merhaba Arkadaşlar,

Eğitim serisinin son makalesinde vuex’i göreceğiz. Vuex, bize component’lar arası haberleşme imkanı ve aynı amaç için kullanılan fonksiyonları tek bir noktada toplama hizmetini sunmaktadır. Örnek vermek gerekirse; Event Emitter Kullanımı başlıklı makalede biz bir component’ın özelliklerini başka bir component’a aktarmak için yeni bir event’i $emit nesnesi ile dışarı aktarıyorduk. Aynı proje içerisinde vuex kullandığımızda böyle bir özelliğe ihtiyaç duymadan tüm component’lara göre yazdığımız aksiyonları tek bir noktada toplayabileceğiz ve değişiklik yapmamız gerektiğinde tüm component’ları gezmek yerine tek bir noktadan yönetim sağlayabileceğiz.

Başka bir eğitim serisi içerisinde projenin tamamının yönetimini vuex ile yapacağız. Bu nedenle uygulamasını uzun uzun burada anlatmayıp hangi fonksiyonun hangi amaç ile kullanılması gerektiğine değineceğim ve minik kod parçaları paylaşacağım.

Kurulum ile başlayalım. Terminale daha önceki makalelerdeki kurulumlarda yaptığımız gibi npm paketini kurmak için kurulum komutunu yazıp çalıştırıyoruz:


npm install --save-dev vuex

Kurulum tamamlandıktan sonra main.js sayfasını açıyoruz ve Vue’nun import edildiği satırın altına Vuex’i import ediyoruz. Vue satırı ile birlikte paylaşıyorum:


import Vue from 'vue'
import Vuex from 'vuex'

Import komutunun alt satırına Vue’nun vuex eklentisini kullanacağına dair komutu yazıyoruz:


Vue.use(Vuex);

Son yazdığımız satırın altına store isminde bir değişken oluşturuyoruz ve bu değişkenin Vuex.Store’dan kalıtım alacağını belirtiyoruz. İçerisine bir adet state ve state içerisine message isminde string bir değer yazalım. Daha sonra kullanım mantığına göre state’ten başlayarak anlatacağım:


const store = new Vuex.Store({
  state: {
    message: 'bilgisayaci.org'
  }
})

Son olarak sayfanın en altındaki Vue’dan kalıtım alarak oluşturulan ve projenin ana yönetim alanı olan kod bloğuna store’u ekliyoruz. Görünümü şu şekilde olmalıdır:


new Vue({
  el: '#app',
  components: { App },
  store,
  template: '<App/>'
})

Burada store yazdığımız satırı store: store şeklinde de güncelleyebiliriz. Eşittirin her iki tarafındaki değer aynı ise tekil kullanım yapabiliyoruz. Eğer oluşturduğumuz değişkenin adı deneme olsaydı store: deneme şeklinde kullanmalıydık. Çünkü vuex’in kullanımı Vue’nun store’u üzerinden yapılabiliyor.

Artık vuex’i projemizin tamamında kullanabiliriz. Ama direkt olarak kullanmaya başlamadan önce vuex altındaki başlıkları ve bu başlıkların kullanım amaçlarını görmemiz gerekir. vuex.vuejs.org adresindeki Core Concepts menüsü altından da görebileceğiniz gibi öğrenmemiz gereken 5 madde var.

State

Değişkenleri ve bu değişkenlere bağlı değerleri barındırdığımız alandır. Diğer başlıklar altında yazacağımız fonksiyonlar ile state değerlerini alır, güncelleriz. Vuex, temel anlamda tek bir state altından yönetilir. State altındaki message isimli değişkeni component içerisinde görüntülemek için {{$store.state.message}} şeklinde çağırmalıyız.

Getters

İçerisinde bulunan “Get” karakterlerinden de anlaşılabileceği gibi herhangi bir veri grubunu çekebilmek için getters’ı kullanırız. Kendisi object tipindedir ve içerisine fonksiyonlar yazarız. Bu fonksiyonlar kendi içerisinde return ile bize istediğimiz değeri gönderir. Getters’ı component içerisinde kullanmak için fonksiyonu oluşturduktan sonra this.$store.getters.firstMessage şeklinde çağırabiliriz.

Mutations

Mutasyonun kelime anlamında olduğu gibi değişim anında kullanılır. State içerisindeki bir değeri değiştirmek istediğimizde mutations objesi içerisindeki bir fonksiyonu çalıştırırız. Mutations altındaki bir fonksiyonu çalıştırmak için ‘commit’ kullanırız. Commit içerisinde yalnızca fonksiyon adı veya fonksiyon adı ile birlikte yeni göndermek istediğimiz değeri kullanabiliriz. Örneğin; this.$store.commit(‘changeMessage’, ‘#vueogreniyoruz eğitim serisi’) satırını çalıştırırsak changeMessage fonksiyonuna ‘#vueogreniyoruz eğitim serisi’ string değerini gönderir.

Actions

Bir önceki başlıkta anlattığım Mutations’ı direkt olarak kullanmayıp actions içerisinden çalıştırmak isteyebiliriz. Neden? Çünkü Actions altındaki fonksiyonlar asenkron olarak çalışabilir, çünkü mutation birden fazla işlemi aynı anda yapmak için uygun değildir ama action tam olarak bunun için yaratılmıştır. Örneğin bir web servis üzerinden veri okunması, okunan verinin store içerisinde bir alana yönlendirilerek değişimin sağlanması, ayrıca getters altından bir fonksiyon yardımı ile verilerin alınması gibi kompleks bir işlem yapmak istediğimizde mutation yerine action kullanırız. Actions altından context.commit ile mutation fonksiyonuna erişebildiğimiz gibi context.state ve context.getters ile state ve getters altındaki fonksiyonlara da erişerek store’un tamamında asenkron olarak etkin olabiliriz. Dispatch komutu ile birlikte kullanırız. Örneğin; this.$store.dispatch(‘triggerChangeMessage’, ‘Vuex kullanımı’) komutu mutations altındaki triggerChangeMessage fonksiyonuna string bir değer gönderir.

Modules

Vuex genel olarak tek bir çatı altından yönetim yapar. Ama şu an yaptığımız anlatımın dışına çıkıp büyük bir projede vuex kullanımı yapacaksak tek bir çatı altında yönetim karmaşık bir yapıyı doğurabilir. İşte bu karmaşıklığın önüne geçmek için ‘Modules’ var. Modules ile birden fazla değişken oluşturup her değişkenin içerisinde kendine ait state,getters,mutations, actions oluşturabiliriz. Örneğin bir haber sitemiz olduğunu düşünürsek spor, seyahat, gündem kategorileri için birbirinden bağımsız state yapıları oluşturup hepsine özel olarak yazılması gereken kodları ayrıştırabiliriz.

Kullanabileceğimiz başlıklar kısaca anlatıldığına göre artık uygulamasına geçebiliriz. main.js içerisinde store değişkenini oluşturduğumuzda message değişkeni eklemiştik. Bu değişkeni App.vue içerisinde çağırarak başlayabiliriz. App.vue template’ini şu şekilde düzenleyelim:


<template>
  <div id="app">
    {{$store.state.message}}
    <hr>
  </div>
</template>

Ekranda değişken içerisine yazdığımız bilgisayaci.org yazısını göreceğiz. State başlığı altında anlatıldığı şekilde çağırmamız string bir değere erişim konusunda yeterli olacaktır.

Sırada getters’ı kullanacağız. Kullanacağımız fonksiyon ile state altındaki message değişkenini çağıracağız. Getters başlığı altında anlatıldığı gibi bir fonksiyon oluşturup return ile bir değer göndermesini sağlayacağız.

main.js içerisindeki store değişkenini aşağıdaki gibi güncelleyelim:


const store = new Vuex.Store({
  state: {
    message: 'bilgisayaci.org'
  },
  getters: {
    firstMessage: state => {
      return state.message
    }
  }
})

getters altına oluşturduğumuz firstMessage fonksiyonu, içerisinde state’i bir parametre olarak alıyor ve return ile state altındaki message değişkenini gönderiyor.

App.vue sayfasını açıyoruz. Template içerisine aşağıdaki iki satırı ekleyelim:


{{ this.$store.getters.firstMessage }}
<hr>

Sayfayı browser üzerinden açtığımızda state altındaki message değişkeni içerisinde yazan bilgisayaci.org yazısını görebiliriz. Ayrıca bir fonksiyon içerisinde nasıl kullanılabileceğini görebileceğimiz küçük bir güncelleme yapabiliriz.

script alanını aşağıdaki gibi güncelleyelim:


<script>
export default {
  data () {
    return {
    }
  },
  created () {
    console.log(this.callMessage())
  },
  methods: {
    callMessage () {
      return this.$store.getters.firstMessage
    }
  }
}
</script>

methods altına oluşturduğumuz callMessage() fonksiyonu içerisinde aynı yukarıda(template içerisinde) kullandığımız satırı ekledik ve başına return yazdık. Bu sayede fonksiyonu çağırdığımız yere return sayesinde bir değer alabileceğiz. Sayfa yüklendiği anda konsola callMessage() içerisinden gelen değeri yazdırabilmek için de created() fonksiyonu oluşturup console.log() içerisinde callMessage() fonksiyonunu çağırdık. Browser’dan sayfayı açıp konsolu kontrol ettiğimizde bilgisayaci.org yazdığını görebiliriz.

Şimdi mutations ile state altındaki message değerini nasıl değiştirebileceğimizi göreceğiz. main.js altındaki store’u aşağıdaki gibi güncelleyelim:


const store = new Vuex.Store({
  state: {
    message: 'bilgisayaci.org'
  },
  getters: {
    firstMessage: state => {
      return state.message
    }
  },
  mutations: {
    changeMessage: (state, value) => {
      state.message = value
    }
  }
})

mutations altına oluşturduğumuz changeMessage fonksiyonu parametre olarak state ve bizim göndereceğimiz yeni değeri alıyor. Fonksiyon içerisinde de yukarıdaki state içerisinde tanımlı message değişkenine yeni değer veriyor.

App.vue sayfası template’i içerisinde aşağıdaki iki satırı ekleyelim:


<button @click="changeStateMessage">Mutations ile message değerini değiştir</button>
<hr>

Daha sonra butonun click event’ına yazdığımız changeStateMessage() fonksiyonunu methods altına tanımlayalım.


changeStateMessage () {
   this.$store.commit('changeMessage', '#vueogreniyoruz eğitim serisi')
}

Sayfayı browser’da görüntülediğimizde butonumuzu göreceğiz. Butona tıklandığında store altındaki changeMessage isimli mutation fonksiyonu çalışacak ve içerisine gönderilen ‘#vueogreniyoruz eğitim serisi’ string değerini alıp state’in message değerini değiştirecektir. Sonucunda message değişkeni yeni değerini alacak ve sayfaya daha önceden iki kere yazdırdığımız bilgisayaci.org satırları da otomatik olarak yeni değere dönüşecektir. Çünkü state üzerinde yaptığımız tüm değişimler anlık olarak dinlenir ve kullanıldıkları yerlerin tamamında güncellenir.

Çalışmamıza actions ile devam ediyoruz. Son olarak yaptığımız mutations işlemini direkt olarak çalıştırmayıp actions içerisinden nasıl yönetebileceğimizi göreceğiz. store’u aşağıdaki gibi güncelleyelim:


const store = new Vuex.Store({
  state: {
    message: 'bilgisayaci.org'
  },
  getters: {
    firstMessage: state => {
      return state.message
    }
  },
  mutations: {
    changeMessage: (state, value) => {
      state.message = value
    }
  },
  actions: {
    triggerChangeMessage: (context, value) => {
      context.commit('changeMessage', value)
    }
  }
})

Oluşturduğumuz actions objesi içerisine triggerChangeMessage() fonksiyonunu ekledik. Fonksiyon, context ile birlikte bizim göndereceğimiz value değerini alıyor. Context, yukarıda actions’ı anlatırken yazdığım gibi store içerisinde genel bir arama ve mutations dışındaki objelere erişirken de bize yardımcı olan nesnedir. Gerektiği yerde context.state ile direkt olarak state değerine veya context.getters ile getters altındaki bir fonksiyona erişebiliriz.

Şu an yalnızca mutations altındaki bir fonksiyona erişmek istediğimiz için ‘context.commit’ kullanarak fonksiyon adı ile birlikte kullanmak istediğimiz yeni string değeri gönderiyoruz.

App.vue sayfasını açalım ve template içerisine aşağıdaki satırı ekleyelim:


<button @click="changeStateMessagewithAction">Actions ile message değerini değiştir</button>

click event’ında çalışmasını istediğimiz changeStateMessagewithAction() fonksiyonunu methods altına tanımlayalım:


changeStateMessagewithAction () {
   this.$store.dispatch('triggerChangeMessage', 'Vuex kullanımı')
}

Gördüğünüz gibi mutation’a gönderdiğimiz yapıya çok yakın bir biçimde çalıştırıyoruz. Mutation’a gönderirken ‘commit’ kullanırken actions içerisindeki uygulamamızda ‘dispatch’ kullanıyoruz. Türkçe ‘sevk etmek’ anlamına gelen dispatch, Actions altındaki bir fonksiyona parantez içerisindeki değeri gönderiyor ve bir değeri direkt olarak mutasyona uğratmak yerine çalıştırdığımız bir eylem sonucunda değişimini sağlıyor.

Sayfamızı çalıştırıp yeni eklediğimiz butona tıkladığımızda sayfanın üst kısmındaki bilgisayaci.org yazılarının ‘Vuex kullanımı’ olarak güncellendiğini görebiliriz.

Modules için de bir şeyler yazmak isterdim ama oluşturduğumuz uygulamada kullanma şansımız pek bulunmuyor. Kullansak bile mantıksız olacağını düşünüyorum. Bu nedenle bu makalede modules özelinde bir geliştirme yapmayacağım. Belki başka bir eğitim serisi içerisinde gerek olur ve kullanırız.

Diğer Kullanım Örnekleri 1

Vuex’i yalnızca bu uygulamada anlattığım gibi kullanmak gibi bir zorunluluğumuz bulunmuyor. Biz şu an minik fonksiyonlar yazdık ama büyük bir proje içerisinde bu fonksiyonlar ve fonksiyon içerisindeki satırlar artabilir. Böyle bir durumda store’u main.js içerisinde tutmak okunurluğu yavaşlatacaktır. Bunun yerine main.js ile aynı dizinde store.js sayfası oluşturup tüm store’u burada barındırabiliriz. Eğer bu şekilde kullanmak istersek;

– store.js sayfasına store değişkenini taşıyalım.
– Artık bu değişkenin kendi dışında bir sayfada kullanılması gerektiği için export kullanalım.
– sayfaya vue ve vuex’i import edip Vue’nun vuex’i kullanacağını belirtelim.

store.js sayfasının görünümü aşağıdaki gibi olmalıdır:


import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    message: 'bilgisayaci.org'
  },
  getters: {
    firstMessage: state => {
      return state.message
    }
  },
  mutations: {
    changeMessage: (state, value) => {
      state.message = value
    }
  },
  actions: {
    triggerChangeMessage: (context, value) => {
      context.commit('changeMessage', value)
    }
  }
})

main.js içerisinden Vuex’in import ve use satırlarını kaldırıyoruz. Import satırlarının en altına store.js import satırını ekliyoruz. main.js’in görünümü şu şekilde olmalıdır:


// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'
import App from './App'
import { store } from './store'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  components: { App },
  store,
  template: '<App/>'
})

Tüm uygulamamızı bu kullanım şeklini kullanarak geliştirip aynı sonucu alabiliriz.

Diğer Kullanım Örnekleri 2

main.js içerisinde veya yine ayrı sayfalarda state, getters, mutations, actions ‘ı ayırarak da kullanabiliriz. Örnek vermek gerekirse mutations’ı bir değişken olarak tanımlayıp aşağıdaki gibi oluşturduktan sonra :


const mutations = {
  increment (state) {
    state.count++
  }
}

Daha önceden oluşturulan ve içerisinde state ile getters eklenmiş olan store’a aşağıdaki gibi eklemeliyiz:


export default new Vuex.Store({
  state,
  getters,
  mutations
})

Eğer tek bir store bizim için yeterliyse bu şekilde bir kullanım ile daha küçük ve daha okunabilir bir yapı kurabiliriz.

Not: Bu ders içeriğinde kullanılan dosyaları görüntülemek için tıklayınız

Reklam

Tüm Yorumlar

Leave a Reply

Your email address will not be published. Required fields are marked *