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:
1npm 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.
1export const FETCH_POSTS_REQUEST = 'FETCH_POSTS_REQUEST';2export const FETCH_POSTS_SUCCESS = 'FETCH_POSTS_SUCCESS';3export 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.
1export const fetchPostsRequest = () => ({2type: FETCH_POSTS_REQUEST,3});45export const fetchPostsSuccess = (posts) => ({6type: FETCH_POSTS_SUCCESS,7payload: posts,8});910export const fetchPostsFailure = (error) => ({11type: FETCH_POSTS_FAILURE,12payload: 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.
1const initialState = {2loading: false,3posts: [],4error: null,5};67const postReducer = (state = initialState, action) => {8switch (action.type) {9case FETCH_POSTS_REQUEST:10return { ...state, loading: true };11case FETCH_POSTS_SUCCESS:12return { ...state, loading: false, posts: action.payload };13case FETCH_POSTS_FAILURE:14return { ...state, loading: false, error: action.payload };15default:16return state;17}18};1920export 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.
1import { createStore, applyMiddleware } from 'redux';2import createSagaMiddleware from 'redux-saga';3import rootSaga from './sagas';4import postReducer from './reducers';56const sagaMiddleware = createSagaMiddleware();78const store = createStore(9postReducer,10applyMiddleware(sagaMiddleware)11);1213sagaMiddleware.run(rootSaga);1415export default store;
4. API ve Saga Yapısı
Axios ile veri çekme işlemini gerçekleştirecek API fonksiyonunu tanımlıyoruz.
1import axios from 'axios';23export const fetchPostsApi = () =>4axios.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.
1import { call, put } from 'redux-saga/effects';2import { fetchPostsApi } from '../api';3import { fetchPostsSuccess, fetchPostsFailure } from '../actions';45function* fetchPostsSaga() {6try {7const response = yield call(fetchPostsApi);8yield put(fetchPostsSuccess(response.data));9} catch (error) {10yield put(fetchPostsFailure(error.message));11}12}1314export 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.
1import { takeLatest } from 'redux-saga/effects';2import { FETCH_POSTS_REQUEST } from '../actions/types';3import fetchPostsSaga from './fetchPostsSaga';45function* watchFetchPosts() {6yield takeLatest(FETCH_POSTS_REQUEST, fetchPostsSaga);7}89export default function* rootSaga() {10yield 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.
1import React, { useEffect } from 'react';2import { useDispatch, useSelector } from 'react-redux';3import { fetchPostsRequest } from '../store/actions';45const PostList = () => {6const dispatch = useDispatch();7const { posts, loading, error } = useSelector(state => state);89useEffect(() => {10dispatch(fetchPostsRequest());11}, [dispatch]);1213if (loading) return <p>Yükleniyor...</p>;14if (error) return <p>Hata: {error}</p>;1516return (17<ul>18{posts.map(post => (19<li key={post.id}>{post.title}</li>20))}21</ul>22);23};2425export 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.