GitHub

Redux ve Redux-Saga ile Asenkron Veri Yönetimi: Adım Adım Uygulamalı

reduxsagaasenkronmiddleware
Redux ve Redux-Saga ile Asenkron Veri Yönetimi: Adım Adım Uygulamalı

Redux nedir?

Redux, JavaScript uygulamalarında kullanılan bir global state yönetim kütüphanesidir. Uygulamanızdaki veriyi merkezi bir yapıda toplar ve bileşenler arasında veri akışını kontrol altında tutmanızı sağlar. Örneğin kullanıcı bilgisi, ürün listesi veya filtre ayarları gibi farklı bileşenlerde kullanılan veriler tek bir Redux store içinde yönetilir.

React'te `useState` ve `useContext` gibi yöntemlerle lokal state yönetimi yapılabilir. Ancak proje büyüdükçe ve sayfalar arası veri paylaşımı arttıkça bu yöntemler yetersiz hale gelir. İşte bu noktada Redux, daha ölçeklenebilir bir çözüm sunar.

Redux-Saga nedir?

Redux-Saga, Redux için geliştirilen bir middleware (ara katman) çözümüdür. Özellikle asenkron işlemleri yönetmek amacıyla kullanılır. Örneğin; bir API'den veri çekmek, bu sırada loading göstermek, hatayı yakalamak ve sonuçları Redux store'a aktarmak gibi tüm süreci Saga ile adım adım kontrol edebilirsiniz.

Redux-Saga'nın en büyük avantajı, generator fonksiyonlar sayesinde asenkron akışı senkron gibi okuyabilmemizdir. Kod daha okunabilir, test edilebilir ve genişletilebilir hale gelir.

Neden Redux-Saga kullanmalıyız?

  • 🔥 Karmaşık asenkron akışları (veri çekme, iptal etme, gecikme) kontrol altında tutar
  • 🔁 `cancel`, `retry`, `debounce`, `throttle` gibi gelişmiş akış kontrol senaryolarını destekler
  • 🧪 Side-effect yönetimi sayesinde test yazmayı ve hata ayıklamayı kolaylaştırır
  • 🧠 Kodun davranışı daha öngörülebilir hale gelir

Bu yazıda ne öğreneceksiniz?

Bu rehberde Redux ve Redux-Saga'nın birlikte nasıl çalıştığını uygulamalı bir örnek proje ile adım adım anlatacağım.

Örnek senaryoda, bir blog API'inden veri çekeceğiz. Veri çekme sürecinde şu konuları işleyeceğiz:

  • Redux action, reducer, store yapılarını oluşturmak
  • Redux-Saga ile API'den veri çekmek
  • Yükleniyor durumu ve hata yönetimi
  • React bileşeni içinde Redux verilerini kullanmak

Haydi şimdi adım adım başlayalım 👇

1. Proje Hazırlığı

Redux, Redux-Saga ve veri çekmek için Axios kütüphanesini projeye dahil ediyoruz:

1
npm install redux react-redux redux-saga axios

2. Redux Yapısını Oluşturmak

Redux’ta 3 temel yapı vardır: actions, reducers, store. Şimdi bunları tek tek oluşturalım.

2.1. Action Types

Uygulamamızda kullanılacak veri akışını temsil eden sabit action türlerini tanımlıyoruz.

1
export const FETCH_POSTS_REQUEST = 'FETCH_POSTS_REQUEST';
2
export const FETCH_POSTS_SUCCESS = 'FETCH_POSTS_SUCCESS';
3
export const FETCH_POSTS_FAILURE = 'FETCH_POSTS_FAILURE';

2.2. Action Creators

API çağrısı başlatma, başarılı sonuç alma ve hata yönetimi için üç farklı action creator tanımlıyoruz.

1
export const fetchPostsRequest = () => ({
2
type: FETCH_POSTS_REQUEST,
3
});
4
5
export const fetchPostsSuccess = (posts) => ({
6
type: FETCH_POSTS_SUCCESS,
7
payload: posts,
8
});
9
10
export const fetchPostsFailure = (error) => ({
11
type: FETCH_POSTS_FAILURE,
12
payload: error,
13
});

2.3. Reducer

Action'lara göre state’i güncelleyen reducer fonksiyonumuzu tanımlıyoruz. `loading`, `posts`, ve `error` olmak üzere 3 state kontrolü yapılıyor.

1
const initialState = {
2
loading: false,
3
posts: [],
4
error: null,
5
};
6
7
const postReducer = (state = initialState, action) => {
8
switch (action.type) {
9
case FETCH_POSTS_REQUEST:
10
return { ...state, loading: true };
11
case FETCH_POSTS_SUCCESS:
12
return { ...state, loading: false, posts: action.payload };
13
case FETCH_POSTS_FAILURE:
14
return { ...state, loading: false, error: action.payload };
15
default:
16
return state;
17
}
18
};
19
20
export default postReducer;

3. Redux Store ve Saga Ortamı

Redux store’u oluşturup `redux-saga` middleware’ini tanımlıyoruz. Uygulamanın tüm asenkron iş akışı burada kontrol altına alınır.

1
import { createStore, applyMiddleware } from 'redux';
2
import createSagaMiddleware from 'redux-saga';
3
import rootSaga from './sagas';
4
import postReducer from './reducers';
5
6
const sagaMiddleware = createSagaMiddleware();
7
8
const store = createStore(
9
postReducer,
10
applyMiddleware(sagaMiddleware)
11
);
12
13
sagaMiddleware.run(rootSaga);
14
15
export default store;

4. API ve Saga Yapısı

Axios ile veri çekme işlemini gerçekleştirecek API fonksiyonunu tanımlıyoruz.

1
import axios from 'axios';
2
3
export const fetchPostsApi = () =>
4
axios.get('https://jsonplaceholder.typicode.com/posts');

5. Worker Saga

Bu saga, API isteğini gerçekleştirir ve sonucu Redux’a aktarır. Başarılıysa veriyi, hata varsa mesajı reducer’a yollar. İlgili action'ı tetikler.

1
import { call, put } from 'redux-saga/effects';
2
import { fetchPostsApi } from '../api';
3
import { fetchPostsSuccess, fetchPostsFailure } from '../actions';
4
5
function* fetchPostsSaga() {
6
try {
7
const response = yield call(fetchPostsApi);
8
yield put(fetchPostsSuccess(response.data));
9
} catch (error) {
10
yield put(fetchPostsFailure(error.message));
11
}
12
}
13
14
export default fetchPostsSaga;

6. Watcher ve Root Saga

`takeLatest` ile yalnızca son tetiklenen isteğin çalışmasını sağlıyoruz. Root saga ise tüm watcher'ları çalıştırır.

1
import { takeLatest } from 'redux-saga/effects';
2
import { FETCH_POSTS_REQUEST } from '../actions/types';
3
import fetchPostsSaga from './fetchPostsSaga';
4
5
function* watchFetchPosts() {
6
yield takeLatest(FETCH_POSTS_REQUEST, fetchPostsSaga);
7
}
8
9
export default function* rootSaga() {
10
yield watchFetchPosts();
11
}

Redux-Saga’da sadece takeLatest değil, farklı kullanım senaryolarına göre tercih edilebilecek birçok watcher efekti vardır:

  • takeEvery – Her tetiklenen action için bir saga başlatır.
    Kullanım: Günlük log kaydı, bildirim gösterme gibi paralel işler.
  • takeLatest – Aynı türde yeni bir action gelirse önceki işlemi iptal eder, sadece sonuncusunu çalıştırır.
    Kullanım: Search bar, form submit gibi son isteğin önemli olduğu durumlar.
  • takeLeading – Sadece ilk action’ı çalıştırır, sonrakileri yoksayar.
    Kullanım: Tek seferlik tıklamalarda (örneğin: ödeme butonu), spam’ı engellemek için.
  • debounce – Belirtilen süre içinde başka action gelmezse en sonuncuyu çalıştırır.
    Kullanım: Otomatik arama (search-as-you-type) gibi gecikmeli tepkilerde.
  • throttle – Belirli aralıklarla gelen action’lardan sadece bir tanesini çalıştırır.
    Kullanım: Scroll, resize gibi yoğun tetiklenen olaylarda performans korumak için.
  • race – Birden fazla işlemi aynı anda başlatır, ilk tamamlanan sonucu üretir.
    Kullanım: Zaman aşımı senaryolarında (örn: “ya 5 saniyede cevap gelirse ya da işlemi iptal et”).

7. Component’te Kullanımı

React bileşeni içinde `useDispatch` ile action gönderiyor, `useSelector` ile Redux state’ini görüntülüyoruz.

1
import React, { useEffect } from 'react';
2
import { useDispatch, useSelector } from 'react-redux';
3
import { fetchPostsRequest } from '../store/actions';
4
5
const PostList = () => {
6
const dispatch = useDispatch();
7
const { posts, loading, error } = useSelector(state => state);
8
9
useEffect(() => {
10
dispatch(fetchPostsRequest());
11
}, [dispatch]);
12
13
if (loading) return <p>Yükleniyor...</p>;
14
if (error) return <p>Hata: {error}</p>;
15
16
return (
17
<ul>
18
{posts.map(post => (
19
<li key={post.id}>{post.title}</li>
20
))}
21
</ul>
22
);
23
};
24
25
export default PostList;

Sonuç

Bu yazıda sıfırdan bir Redux ve Redux-Saga mimarisi kurarak, bir API'den veri çekme ve asenkron akış yönetimini adım adım inceledik.
Bu yapı, özellikle orta-büyük projelerde veri kontrolünü merkezi bir yapı altında tutarak bakım kolaylığı ve test edilebilirlik sağlar.