Choo Framework, Nedir, Nasıl Kullanılır — II?

Dün Choo ile basit bir uygulamayı nasıl oluşturabileceğimizi dair bir şeyler anlattım. Şimdi ise, işin biraz daha karmaşıklaştığı ama, daha mühim bir noktayı anlatmaya çalışacağım. Uygulama içerisinde veri yönetiminin nasıl yapılacağı.

Bir önceki yazıda da belirttiğim gibi, yazım şekli ve yaklaşım fazlasıyla Redux’u andırıyor. Reducer’lara benzeyen emitter’ların olduğunu düşünebilirsiniz. Değişmesini istediğimiz verinin, store.js içerisindeki, alacağı değerleri emitter yolu ile iletiyoruz. Emitter’lar birer fonksiyon ve ister sabit bir değeri isterseniz de sizin gönderdiğiniz bir değeri state içerisindeki veriye eşitleyebiliyor. Uygulamanın herhangi bir yerinden emitter’a erişebilmek için, route’ların içerisinde component’ları state.cache yöntemi ile uygulamanın içine dahil etmek yeterli oluyor.

Son bıraktığımız yerde, uygulamamız sabit bir metin içeriyordu. Öncelikle, bir servisten de gelebileceğini düşünerek, store içerisinde örnek bir veri oluşturmamız gerekiyor. Sonrasında bu verileri uygulamanın çeşitli yerlerinde yöneteceğiz.

Store

Store içerisinde öncelikle örnek bir array oluşturmamız gerekiyor.

[
 {
    title: 'Example todo item 1',
    completed: true
  },
  {
    title: 'Example todo item 2',
    completed: false
  }
]

Store, saf bir fonksiyon ve içerisinde kullanılmak üzere iki değeri var. Birinci parametre ile verilerinizi oluşturuyorsunuz. Buna ctx ya da state diyebilirsiniz. İkinci parametre ise emitter. Emitter’lar ile de verilerinize müdahalede bulunabileceğiniz fonksiyonları oluşturuyorsunuz. Bu iki parametreyi de kullandıktan sonra fonksiyonunuzu export ederek, main.js içerisinde kullanılabilir hale getirebiliriz.

store.js

Şu an elimizde, uygulama içerisinde dağıtabileceğimiz bir adet array ve bir adet fonksiyon söz konusu. all array’i ile bir liste oluşturabilir, updateItem emitter’i ile de bu listeye müdahale edebiliriz. Görüldüğü üzere müdahale etme kısmı dışarıdan herhangi bir değer almaksızın sabit bir eşleştirme yapıyor. Bu eşitlemenin ardından render metodunu çağırıyoruz.

Ek olarak şunu söylemek gerekiyor. Emitter kendi içerisinde çelitli özellikler barındırıyor. Bunlardan biri de DOM yüklendiğinde istediğiniz fonksiyonların çalıştırılması. Bir nevi React’taki componentDidMount gibi düşünülebilir.

emitter.on('DOMContentLoaded', () => {
  console.log('mounted on the DOM')
})

Store içerisindeki bu şekildeki bir kullanımda DOMContentLoaded event’ini yakalayabiliyorsunuz.

List & Item

List ve Item adında bir component oluşturacağız. Sonrasında bu component’lerin home.js içerisinde render edilip store içerisinde oluşturduğumuz all array’ine erişmesini bekleyeceğiz.

Öncelikle ‘stateful’ ve saf fonksiyon olmak üzere, iki türlü şekilde component’ları oluşturabiliyoruz. List component’ini stateful şekilde, yani class kullanarak oluşturacağız. Çünkü istediğimiz, home.js içerisinden render edildiğinde doğrudan state ve emit’lere erişebilmesi. Home.js içerisinde kullanacağımız ‘state.cache’ yöntemi bunun için var.

// list.js
import html from 'choo/html'
import Component from 'choo/component'
// load components
import Item from './item'
class List extends Component {
  constructor (name, { all }, emit) {
    super(name)
      this.data = all
      this.emit = emit
      this.handleItem = this.handleItem.bind(this)
    }
  update () {
    return true 
  }
  handleItem () {
    this.emit('updateItem')
  }
  createElement () {
    return html`
      <div class=${name}>
        <button
type="button"
onclick=${this.handleItem}>
Change
</button>
        <ul>
          ${this.data.map((item, index) => Item(item, index))}
        </ul>
      </div>
    `
  }
}
export default List

Component yönetmini choo/component içerisinden çağırdık. Bu bize oluşturduğumuz class’a çeşitli kalıtsallıkları eklememiz için yardımcı oluyor. Böylelikle belli metodlara erişebiliyoruz. Örneğin update() methodu ile oluşturduğumuz component’in herhangi bir veri değişmesi durumunda kendini değiştirip değiştirmeyeceğini belirleyebiliyoruz. Bu kullanımda return true olduğu için herhangi bir veri değişiminde List component’inin da tekrardan render edilebileceğini söyleyebiliriz.

createElement ile component’ın DOM yapısını oluşturuyoruz. İhtiyaç duyulduğu yerde çocuk bileşenleri de yine burada döndürüyoruz.

Oluşturduğumuz class’ın contructor’undan eriştiğimiz state ve emit ile de önce store içerisindeki veriyi tarayıp sonrasında da değiştirmek için tetikleyeceğimiz fonksiyonu oluşturabiliyoruz. Burada kullandığımız yöntemler pure javascript ile de kullanabilen ‘template literals’ ve ‘class’ özelliklerinden ibaret.

Sonrasında store’dan çektiğimiz veriyi döngüye aldıktan sonra tekrardan Item adlı component’la ekrana yazılmasını istiyoruz. Bunun için oluşturduğumuz item.js’i list.js içerisinde çalıştırmamız yeterli.

import html from 'choo/html'
function Item ({ title, completed }, id) {
  return (
    html`
      <li id=${id}>
        <h4>${title}</h4>
        <input type="checkbox" checked=${completed} />
      </li>
    `
  )
}
export default Item

Fonksiyon ile oluşturduğumuz item.js kendisine gelen veriden bir template oluşturma görevini görüyor. Ul içerisindeki li elementlerini oluşturuyor. Return ettiği değer html yöntemi kullanılarak oluşturulmuş element olduğu için de list.js içerisinde ihtiyacı olan props’ları verdikten sonra bir fonksiyon gibi çağırmak yeterli oluyor.

Home

Şimdi veriyi çocuk bileşenlerde kullanabilmek için tekrardan home.js’e dönüyoruz.

import html from 'choo/html'
// load components
import List from '../components/list'
function home (state, emit) {
  return (
    html`
      <div>
        ${state.cache(List, 'list').render()}
      </div>
    `
  )
}
export default home

Oluşturduğumuz List adındaki stateful component’i burada state.cache yöntemi ile render ediyoruz. Böylelikle state ve emit’leri List içerisinde erişilebilir kılıyoruz.

Şimdi elimizde List.js içerisinden button ile store içerisindeki veriyi sabit bir değere eşitleyerek değiştirebildiğimiz bir uygulama bulunuyor. Eğer isterseniz, store içerisindeki emitter’a parametre göndererek all array’ine dinamik bir şekilde erişip, istediğiniz değerlere de eşitleyebilirsiniz.

Şimdiye kadar yaptığımız değişiklikleri repo’dan çekip yerelinizde çalıştırabilirsiniz.