React - Redux Yapısına Giriş

Merhaba, React.js çalışmaya ara versemde devam ediyorum. Bu yazıda hem dosya yapısı hem de temel yapıyı ele alacağım.

Öncelikle aşağıdaki komut ile basit bir React projesi oluşturalım. Anlayacağınız üzere basit bir counter (sayaç) uygulaması olacak.

npx create-react-app counter-app

Proje kurulumu tamamlandıktan sonra VS Code ile açalım ve terminal ekranına aşağıdaki komutu yazarak ilgili paketleri kuralım.

npm install redux react-redux redux-devtools-extension --save

Tarayıcınıza Redux DevTools eklentisini ( uzantısını ) kurmayı unutmayalım.

Daha sonra, "src" klasörü altına şu klasörleri oluşturalım.

  1. actions
  2. components
  3. constants
  4. data
  5. reducers
  6. store

Şimdi bunları yavaş yavaş dolduracağız. Zaten basit bir şey yapacağız.

Components içine "Counter.jsx" dosyası oluşturalım ve içine aşağıdaki kodları yapıştıralım.

import React from 'react'

const Counter = () => {

  let handleIncrease = () => {
  }

  let handleDecrease = () => {
  }

  return (
    <div>
      <button onClick={() => handleDecrease()}>-</button>
      state: 0
      <button onClick={() => handleIncrease()}>+</button>
    </div>
  )
}

export default Counter

App.css dosyası içindekileri silelim ve şunları yazıverelim.

.App {
  text-align: center;
  margin-top: 15px;
}

button {
  background-color: #4caf50;
  color: white;
  padding: 14px 20px;
  margin: 8px 8px;
  border: none;
  cursor: pointer;
}

Ardından da App.js dosyasını şu hale getirelim.

import './App.css'
import Counter from './components/Counter'

function App() {
  return (
      <div className="App">
        <Counter />
      </div>
  )
}

export default App

Evet.. Temel şeylerimizi tamamladık sayılır.

constants klasörü içine "action-types.js" dosyası oluşturalım ve içine şu kodları yazalım. Bu değerleri her yerde kullanabilmek için ayrı bir dosya olarak hazırlıyoruz.

export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'

 

actions klasörü içine ise iki adet dosya oluşturacağız. Adından da anlaşılabileceği üzere sistemdeki tüm aksiyonları buradan yöneteceğiz.

Oluşturacağımız dosyalar "index.js" ve "counter.js" olacak.

"counter.js" dosyasını açalım ve aşağıdaki kodları yazalım.

/* constants içinde oluşturduğumuz action-types ları buradan çekiyoruz.
 İçinde birden fazla olabileceği için tek tek yazmak yerine
 * as actionTypes olarak hepsini çekiyoruz */

import * as actionTypes from '../constants/action-types'

/* increment metodu. İçine bir değer alır.
   Burada payload u gönderilecek data olarak düşünelim.
 */
export const increment = (value) => {
  return {
    type: actionTypes.INCREMENT, // action-types içinden geliyor.
    payload: value,
  }
}

/* decrement metodu. İçine bir değer alır.
   Burada payload u gönderilecek data olarak düşünelim.
 */
export const decrement = (value) => {
  return {
    type: actionTypes.DECREMENT, // action-types içinden geliyor.
    payload: value,
  }
}

 

Bu ve bunun gibi bir çok js dosyası burada bulunabilir. Örneğin kullanıcılar ile ilgili işlemler için "users.js" adında bir tane ekleyebilirsiniz. İçine yazacağınız metotları size ait olacak.

"index.js" dosyasını açalım ve içine aşağıdaki kodları yazalım.

// counter.js içindeki metotları dahil ettik.
import { increment, decrement } from './counter'

// Hepsini teker teker export etmektense actions adında bir obje içinde export edelim.
let actions = { increment, decrement }

export default actions

 

Evet, temel redux işlemlerini tamamlamak üzereyiz. Aksiyonlarımızı yazdık. Şimdi bu aksiyonlara göre yöneteceğimiz state in değişeceği dosyaya gidelim.

reducers klasörünün altına gelelim. Burada da iki adet dosya oluşturacağız. Bunlar "index.js" ve "counter.js" dosyaları. Counter gibi onlarca olabilir. Hepsini tek tek export edip karışıklık olmasındansa index içinde hepsini birleştireceğiz.

counter.js dosyamızı açalım. İçine şu kodları yazalım. Sanırım anlaşılır olacak.

import * as actionTypes from '../constants/action-types'

// Başlangıç için bir state tanımlıyoruz.
const initialState = { sayi: 0 }

/* actions içindeki metotların gönderdiği değerlere göre bir 
switch-case yapısı düzenleyip state değerimizi güncelliyoruz. */
export const counterReducer = (state = initialState, action) => {

  switch (action.type) {
    case actionTypes.INCREMENT:
      return { ...state, sayi: state.sayi + action.payload }

    case actionTypes.DECREMENT:
      return { ...state, sayi: state.sayi - action.payload }

    default:
      return state
  }
}

Aslında anlaşılıyor değil mi?

State içindeki sayi değerimiz başlangıçtaki değeri 0. Artır dediğimizde arttıracak, azalt dediğimizde azaltacak.

Şimdi sıra reducers klasörü altındaki index.js dosyasına da şu satırları yazalım.

// Burada oluşturduğumuz tüm reducer ları ekleyeceğiz. 
// Biz zaten 1 tane oluşturmuştuk.
import { counterReducer } from './counter'

// Tüm reducer ları birleştireceğimiz metot diyelim. Burası önemli :)
import { combineReducers } from 'redux'

// Hepsini allReducers altında birleştirelim.
let allReducers = combineReducers({
  counterReducer,
  // userReducer,
  // kategoriReducer, vs vs..
})

export default allReducers

 

Ve yavaş yavaş sona yaklaşıyoruz.

store içine de "index.js" dosyası oluşturalım ve içine de şunları yazalım.

/* store oluşturmak için "createStore" ekliyoruz. 
   Middleware kullanmak isterseniz diye ki ileride kullanırız
   elimiz alışsın bunu da dahil ediyoruz.
*/
import { createStore, applyMiddleware } from 'redux'

// Tüm reducers ları dahil ettik. Hatırlarsanız birleştirmiştik.
import allReducers from '../reducers'

// Tarayıcı da extension kurduysanız görme amaçlı
import { composeWithDevTools } from 'redux-devtools-extension'

// Burada store oluşturuluyor.
let store = createStore(allReducers, composeWithDevTools(applyMiddleware()))

export default store

 

Ve gelelim son adıma.

App.js dosyamızı açalım ve şu şekilde yeniden düzenleyelim.

import './App.css'

// componentimiz burada
import Counter from './components/Counter'

/* Burası zorunlu. 
  Oluşturmuş olduğumuz store u bu kapsayıcı içine alacağız. 
  Her yerden erişilmesi için.
*/
import { Provider } from 'react-redux'

// store umuzu dahil edelim.
import store from './store'

function App() {
  
  return (
    // Esprimiz tam olarak bu. 
    <Provider store={store}>
      <div className="App">
        <Counter />
      </div>
    </Provider>
  )
}

export default App

 

Evet, store oluşturduk. Aksiyonlarımızı yazdık. State güncellerimizi tutacağımız reducer larımızı yazdık.

Şimdi sıra geldi bunları kullanmaya.

components altındaki Counter.jsx dosyamızı açalım ve şu şekilde değiştirelim.

import React from 'react'

// aksiyonları göndermek ve state değerini almak için kullanılıyor
import { useDispatch, useSelector } from 'react-redux'

// aksiyonları alıyoruz.
import actions from '../actions'

const Counter = () => {

  // aksiyonları göndermek için gerekli
  let dispatch = useDispatch()

  
  // useSelector ile kullanmak istediğimiz state değerini alıyoruz.
  // reducers klasörü altındaki index içindeki değerimiz
  let counterState = useSelector((state) => state.counterReducer)

  let handleIncrease = () => {
    /* + butonuna basıldığında,
     dispatch ile actions altındaki increment metodu çalıştırılıyor */
    dispatch(actions.increment(5))
  }

  let handleDecrease = () => {
  /* - butonuna basıldığında,
     dispatch ile actions altındaki decrement metodu çalıştırılıyor.
     counterState içindeki sayi degeri > 0 olduğu müddetçe çalışsın demişiz.
  */
    if (counterState.sayi > 0) dispatch(actions.decrement(5))
  }

  return (
    <div>
      <button onClick={() => handleDecrease()}>-</button>
      state: {counterState.sayi}
      <button onClick={() => handleIncrease()}>+</button>
    </div>
  )
}

export default Counter

 

Evet, unuttuğum ya da kaçırdığım bir yer yok ise sistem çalışmalı.

Ben her halükarda github a atıyorum. Buraya tıklayıp kontrol edebilirsiniz.

Evet şimdilik bu kadar..

 

 

46 Görüntülenme

Yorum Yap