Redux Toolkit ile API işlemleri

Metin AKSU
3 min readMar 11, 2024

--

Bir önceki yazıda RTK(Redux Toolkit)’in uygulamamıza nasıl dahil edileceğini ve aksiyonların nasıl işlediğini görmüştük. Bu yazıda ise, API‘den veri çekmeyi göreceğiz.

API’den veri çekme işlemi, normal şartlarda ilgili sayfalarda yapılır ve verinin gösterimi o sayfalarda yapılır.

Ancak çektiğimiz veri ile yapacağımız işlemlerin sonucu, diğer sayfaları/komponentleri de etkiliyorsa, orada ki değerlerinde değişmesi gerekiyorsa, bu durumda bu işlemi state üstünden yapmak daha mantıklı olacaktır.

Ben genelde kullanıcı ile ilgili verileri bu yüzden state üstünde tutuyorum. Çünkü bu verilere birden çok sayfada/komponentte erişmem gerekiyor. En basitinden kullanıcı giriş yapmış mı yapmamış mı, giriş yap butonunu mu göstereceğim, yoksa kullanıcı işlemleri butonunu mu göstereceğimin ayrımını, state üstünden kullanıcı verisini kontrol ederek yapıyorum.

Bunun için diğer yazıda gösterdiğim kurulumları yaptığınızı varsayıp, onun üstünden devam ediyorum.

API üstünden veri çekmek için slice dosyası içinde RTK’nın createAsyncThunk metodunu kullanıyoruz.

Önce kodun tamamını verip, detayları açıklayalım.

// userInfoSlice.js

import axios from "axios";
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

export const getUserInfo = createAsyncThunk("getUserInfo", async () => {
const response = await axios.get("https://jsonplaceholder.typicode.com/users/1");
const data = await response.data;
return data;
});

const userInfoSlice = createSlice({
name: "userInfo",
initialState: {
userInfo: {},
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(getUserInfo.fulfilled, (state, action) => {
// işlem başarılı olduğunda yapılacak işlemler
state.userInfo = action.payload;
})
.addCase(getUserInfo.pending, (state) => {
// işlem başladığında yapılacak işlemler
state.userInfo = {};
})
.addCase(getUserInfo.rejected, (state) => {
// işlem hatalı olursa yapılacak işlemler
state.userInfo = {};
});
},
});

export default userInfoSlice.reducer;

axios’ın artık hemen her yerde fetch’in yerini aldığını biliyorsunuzdur.

Bir slice dosyasında birden çok createAsyncThunk işlemi yapabilirsiniz.

Gördüğünüz gibi API’den veri çekerken artık reducers kısmını kullanmıyoruz. Bunun yerine extraReducers diye bir bölüm gelmiş durumda. Bu bölümde addCase kısmında, aynı createAsyncThunk işlemi için 3 farklı durum eklendiğini görüyorsunuz. fulfilled, pending, rejected. Açıklamaları kod içinde yazıyor.

Bir createAsyncThunk işlemi için bu üç tanımın hepsini yazmanız şart değil. Ama fulfilled kısmını yazmanız şart gibi. Çünkü çektiğiniz veriyi state’e aktaracak olan o kısım.

Pending kısmını belki loading işlemleri ve bir yükleniyor animasyonu için kullanabilirsiniz. Rejected bölümünü de işlem başarısız olduğunda bir uyarı göstermek amacıyla kullanabilirsiniz.

getUserInfo metodunu bu şekilde tanımlayıp bırakmak yetmiyor elbette. Bunu bir sayfadan çağırmanız gerekiyor ki, gelen veriler userInfo isimli state’e aktarılabilsin.

Önce bunu store.js dosyamıza bağlayalım.

// store.js 

import { configureStore } from "@reduxjs/toolkit";
import userInfoReducer from "./userInfoSlice";

export const store = configureStore({
reducer: {
userinfo: userInfoReducer,
},
});

Ve bunu App.js dosyamız üstünden çağıralım.

// App.js

import { useEffect } from "react";

import { useDispatch } from "react-redux";
import { getUserInfo } from "./redux/userInfoSlice";

function App() {
const dispatch = useDispatch();

useEffect(() => {
dispatch(getUserInfo());
}, [dispatch]);

return (
<div>
<h1>Hello World</h1>
</div>
);
}

export default App;

Artık kullanıcının verilerine uygulama içindeki diğer sayfalardan erişebilirsiniz.

import { useSelector } from "react-redux";

const UserView = () => {
const userData = useSelector((state) => state.userinfo.userInfo);

return (
<div>
User Data : {JSON.stringify(userData)}
</div>
);
};

export default UserView;

Biz burada sabit bir kullanıcı id numarası verip, bunu getUserInfo ile çektik. Ama isterseniz dispatch işleminde getUserInfo metoduna parametre olarak bir değer geçerek de kullanabilirsiniz. Bu durumda metodu şu şekilde düzenlemeniz gerekir.

export const getUserInfo = createAsyncThunk("getUserInfo", async (userId) => {
const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`);
const data = await response.data;
return data;
});

Artık bunu ilgili yerlerde dispatch(getUserInfo(123)) şeklinde kullanabilirsiniz.

Burada reducers altında herhangi bir işlem tanımlamamış olmamız, createAsyncThunk işlemi yapılan sayfalarda reducers kullanılmıyor gibi bir algı oluşturmasın üzerinizde. Tam aksine, ikisi bir arada kullanılabiliyor. Hatta API’den çekerek extraReducers ile üzerinde işlem yaptığınız değerlere normal reducers ile de müdahale edebiliyorsunuz.

Küçük bir örnek verelim. Mesela reducers kısmında bir logout işlemi tanımlayalım.

  reducers: {
logout: (state) => {
state.userInfo = {};
localStorage.removeItem("token");
window.location.href = "/logout";
},
},

Elbette bu logout işlemini sayfa altından (userInfoSlice.js) export etmeyi unutmuyoruz.

export const { logout } = userInfoSlice.actions;

İlgili sayfada import ve dispatch ile işlemi uyguluyoruz.

import { useDispatch } from "react-redux";
import { logout } from "../redux/userInfoSlice";

const UserPanel = () => {
const dispatch = useDispatch();
const handleLogout = () => {
dispatch(logout());
};

return (
<div>
<button onClick={handleLogout}>Logout</button>
</div>
);
};

export default UserPanel;

Konuyla ilgili data detaylı bilgiye RTK’nın sayfasından ulaşabilirsiniz.

https://redux-toolkit.js.org/api/createAsyncThunk

Redux Toolkit’e hızlı giriş yazıma da buradan ulaşabilirsiniz.

https://medium.com/@metinaksu/redux-toolkit-h%C4%B1zl%C4%B1-giri%C5%9F-0accbb8cde7c

--

--