Bilinmesi Gereken React Kütüphaneleri - Redux Saga

Redux Saga

Redux-Saga, JavaScript ile yazılmış bir kütüphanedir ve React uygulamalarında veri yönetimini (state management) ve yan etkileri (side effects) yönetmeyi kolaylaştırır. İşte Redux-Saga'nın ne işe yaradığına dair bazı temel noktalar:

  1. Yan Etki Yönetimi: API çağrıları, zaman aşımı işlemleri ve diğer asenkron işlemler gibi yan etkileri yönetir.
  2. Temiz ve Test Edilebilir Kod: Yan etkileri yönetmek için yazılan kodları daha temiz ve test edilebilir hale getirir.
  3. Asenkron İşlemler: Redux eylemleri (actions) ile asenkron işlemleri daha kolay bir şekilde yönetir.
  4. Esnek Kontrol: Eylemlerin (actions) yakalanması ve işlenmesi üzerinde daha fazla kontrol sağlar.
  5. Yönetilebilir Akışlar: Karmaşık akışları ve iş mantığını daha yönetilebilir hale getirir.

Redux-Saga, generator fonksiyonları kullanarak çalışır ve bu sayede yazılım geliştiricilere uygulamalarındaki karmaşık asenkron iş akışlarını yönetme konusunda büyük esneklik sağlar. Örneğin, bir API çağrısı yaparken belirli bir eylem (action) göndermek, ardından çağrının başarılı veya başarısız olmasına göre farklı eylemler göndermek için Redux-Saga kullanabilirsiniz.

Redux-Saga Örneği

Bir switch butonun backend'e lamba durumunu gönderdiği ve backend'den olumlu cevap geldiğinde switch durumunun güncellendiği bir uygulama:

1. App.js

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { toggleLightRequest } from './redux/actions';

function App() {
  const dispatch = useDispatch();
  const lightStatus = useSelector(state => state.lightStatus);
  const loading = useSelector(state => state.loading);

  const handleToggle = () => {
    dispatch(toggleLightRequest(!lightStatus));
  };

  return (
    <div>
      <h1>Lamba Durumu: {lightStatus ? 'Açık' : 'Kapalı'}</h1>
      <button onClick={handleToggle} disabled={loading}>
        {loading ? 'Güncelleniyor...' : 'Durumu Değiştir'}
      </button>
    </div>
  );
}

export default App;

2. redux/actions.js

export const TOGGLE_LIGHT_REQUEST = 'TOGGLE_LIGHT_REQUEST';
export const TOGGLE_LIGHT_SUCCESS = 'TOGGLE_LIGHT_SUCCESS';
export const TOGGLE_LIGHT_FAILURE = 'TOGGLE_LIGHT_FAILURE';

export const toggleLightRequest = (status) => ({
  type: TOGGLE_LIGHT_REQUEST,
  payload: status,
});

export const toggleLightSuccess = (status) => ({
  type: TOGGLE_LIGHT_SUCCESS,
  payload: status,
});

export const toggleLightFailure = () => ({
  type: TOGGLE_LIGHT_FAILURE,
});

3. redux/reducer.js

import { TOGGLE_LIGHT_SUCCESS, TOGGLE_LIGHT_FAILURE, TOGGLE_LIGHT_REQUEST } from './actions';

const initialState = {
  lightStatus: false,
  loading: false,
  error: null,
};

export const lightReducer = (state = initialState, action) => {
  switch (action.type) {
    case TOGGLE_LIGHT_REQUEST:
      return { ...state, loading: true };
    case TOGGLE_LIGHT_SUCCESS:
      return { ...state, lightStatus: action.payload, loading: false };
    case TOGGLE_LIGHT_FAILURE:
      return { ...state, loading: false, error: 'Lamba durumu güncellenemedi.' };
    default:
      return state;
  }
};

4. redux/sagas.js

import { takeLatest, call, put } from 'redux-saga/effects';
import { TOGGLE_LIGHT_REQUEST, toggleLightSuccess, toggleLightFailure } from './actions';

function* toggleLightSaga(action) {
  try {
    const response = yield call(apiToggleLight, action.payload); // Backend'e istek gönder
    if (response.ok) {
      yield put(toggleLightSuccess(action.payload)); // Başarılıysa durumu güncelle
    } else {
      yield put(toggleLightFailure());
    }
  } catch (error) {
    yield put(toggleLightFailure());
  }
}

function apiToggleLight(status) {
  return fetch('/api/toggle-light', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ status }),
  });
}

export default function* rootSaga() {
  yield takeLatest(TOGGLE_LIGHT_REQUEST, toggleLightSaga);
}

5. redux/store.js

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { lightReducer } from './reducer';
import rootSaga from './sagas';

const sagaMiddleware = createSagaMiddleware();
const store = createStore(lightReducer, applyMiddleware(sagaMiddleware));

sagaMiddleware.run(rootSaga);

export default store;

6. index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Backend Örneği (/api/toggle-light)

app.post('/api/toggle-light', (req, res) => {
  const { status } = req.body;
  // Backend mantığını buraya ekleyin (Örn: veri tabanına kaydet)
  res.json({ success: true });
});

Bu örnekte, App.js içerisinde bir switch butonu var. Butona basıldığında Redux-Saga üzerinden backend'e lamba durumu gönderiliyor ve eğer işlem başarılı olursa butonun durumu güncelleniyor.

Bilgi Akışı

Bu örnekteki bilgi akışı şu şekilde gerçekleşiyor:

  1. App.js
    dispatch(toggleLightRequest(!lightStatus));
    → Butona basıldığında actions.js içindeki TOGGLE_LIGHT_REQUEST eylemi dispatch edilir.
  2. redux/actions.js
    toggleLightRequest fonksiyonu çağrılır.
    return { type: TOGGLE_LIGHT_REQUEST, payload: status }; ile yeni durum redux/reducer.js içindeki lightReducer'a gönderilir.
  3. redux/reducer.js
    lightReducer içinde actions.js'den gelen TOGGLE_LIGHT_REQUEST eylemi yakalanır.
    loading durumu true olarak güncellenir.
  4. redux/sagas.js
    takeLatest(TOGGLE_LIGHT_REQUEST, toggleLightSaga) ile actions.js'den gelen TOGGLE_LIGHT_REQUEST eylemi yakalanır.
    toggleLightSaga fonksiyonu çalışır.
  5. redux/sagas.js
    const response = yield call(apiToggleLight, action.payload);
    apiToggleLight fonksiyonu çağrılarak backend'e istek gönderilir.
  6. redux/sagas.js
    function apiToggleLight(status)
    fetch API ile POST isteği /api/toggle-light adresine yapılır.
  7. Backend (/api/toggle-light)
    app.post('/api/toggle-light', (req, res) => {...})
    → Gelen istek işlenir ve ışık durumu kaydedilir.
  8. Backend (devamı)
    res.json({ success: true });
    → Başarı yanıtı döner.
  9. redux/sagas.js
    if (response.ok) { yield put(toggleLightSuccess(action.payload)); }
    → Başarılı yanıt alındığında actions.js içindeki TOGGLE_LIGHT_SUCCESS eylemi dispatch edilir.
  10. redux/reducer.js
    lightReducer içinde actions.js'den gelen TOGGLE_LIGHT_SUCCESS eylemi yakalanır.
    → Işık durumu güncellenir ve loading durumu false olarak ayarlanır.
  11. App.js
    → Redux state güncellendiğinde bileşen yeniden render edilir.
    → Işık durumu ve buton durumu güncellenir (buton üzerindeki metin değişir).

Comments