Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kaplanh/redux-redux-toolkit-example


https://github.com/kaplanh/redux-redux-toolkit-example

axios react redux-thunk redux-toolkit

Last synced: 3 days ago
JSON representation

Awesome Lists containing this project

README

        

# Redux Toolkit

https://redux-toolkit.js.org/tutorials/quick-start

## installation

pnpm add @reduxjs/toolkit
pnpm add react-redux

# Redux Toolkit Ornegi

## `Kurulum`

```
npm install || pnpm install || yarn
```

## `Kullanilan Kutuphaneler`

- `@reduxjs/toolkit`
- `react-redux`
- `axios`
- `react-router-dom`
- `@mui/material-ui`
- `@emotion/react`
- `@emotion/styled`

## `Kullanilacak API`:

- https://newsapi.org/
(Get Key butonuna tiklanarak key alinabilir)

- URL:
const url = `https://newsapi.org/v2/top-headlines?country=tr&apiKey=${API_KEY}`;

## `Kullanilacak Araclar`

- `Redux Dev Tools` : Chrome uzerinde calisan ve global state uzerinde yapilan tum degisikliklerin takip edilmesini saglayan tarayici uzantisidir. Indirmek icin [tiklayiniz.](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?utm_source=chrome-ntp-icon)`

# Redux Toolkit

## 1-src/features/altinda ne kadar slice varsa slicelar yazilir

- authSlice.jsx

```jsx
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
user: "",
};

//? Slice ile bir global state'in hem action type'lari , hem action creator fonksiyonlarini hem de reducer'i tek bir hamlede olusturabiliriz.

const authSlice = createSlice({
name: "auth", //? action type'ı olusturmak icin
initialState, //? state'in bslangic degeri icin
reducers: {
//? action creator fonks. ve reducer icin
setUser: (state, action) => {
state.user = action.payload;
},
clearUser: (state) => {
state.user = "";
},
},
});

//? olusan action fonksiyonları sliceAdi.actions 'dan destructure edilerek export edilir.
export const { setUser, clearUser } = authSlice.actions;

//? yazilan slice'in reducer'i sliceAdi.reducer seklinde export edilmelidir.
export default authSlice.reducer;
```

- newsSlice.jsx

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

const initialState = {
news: [],
loading: false,
error: false,
};

export const getNews = createAsyncThunk(
"getNewsFunc", //? action type name

async () => {
const API_KEY = "1a1a999e0d7240a6bd2dead87bcca78e";
const url = `https://newsapi.org/v2/top-headlines?country=us&apiKey=${API_KEY}`;

const { data } = await axios(url);
console.log(data);
return data.articles;
}
);

const newsSlice = createSlice({
name: "news",
initialState,
reducers: {
clearNews: (state) => {
state.news = [];
},
},
//? createAyncThunk metedo bir middleware olarak API gibi dis kaynakli isteklerin redux ortaminda olsuturulmasini saglar. Ancak API^deki durumlara gore state'lerin guncellenmesini saglamaz. Bunun icin slice icersiindeki extraReducer kismi kullanilir.

//? API isteklerinde 3 farkli alt durum meydana gelir. Bunlar baslama (pending), basarili bitme (fullfilled) ve basariz bitme (rejected) dir.

extraReducers: (builder) => {
builder
.addCase(getNews.pending, (state) => {
state.loading = true;
})
.addCase(getNews.fulfilled, (state, action) => {
state.news = action.payload;
state.loading = false;
})
.addCase(getNews.rejected, (state) => {
state.error = true;
state.loading = false;
});
},
});

export const { clearNews } = newsSlice.actions;

export default newsSlice.reducer;
```

## 2- src/app/store.jsx ile store olusturulur.

- store.jsx

```jsx
import { configureStore } from "@reduxjs/toolkit";
import authReducer from "../features/authSlice";
import newsReducer from "../features/newsSlice";

export const store = configureStore({
reducer: {
auth: authReducer,
api: newsReducer,
},
devTools: process.env.NODE_ENV !== "production",
//? eger gelistirme asamasi prodcution ise o zaman yukaridaki ifade false dondurur ve dolayisiyla devTool kullanima kapali olur.
});
```

## 3- olusan stor'a tüm componentlerden ulasabilmek icin App.jsx içine Provider eklenir

- App.jxs

```jsx
import { Provider } from "react-redux";
import AppRouter from "./router/AppRouter";
import { store } from "./app/store";

function App() {
return (



);
}

export default App;
```

## 4- store daki state'i doldurmak ve ihtiyac olan componentlerde kullanmak için useDispatch() hooku ve useSelector() hooku kullanılır

- Login.jsx (useDispatch() ile statei doldurmak icin)

```jsx
import * as React from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Link from "@mui/material/Link";
import Box from "@mui/material/Box";
import Avatar from "@mui/material/Avatar";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";
import { useState } from "react";
import { useDispatch } from "react-redux";
import { setUser } from "../features/authSlice";
import { useNavigate } from "react-router-dom";

export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const dispatch = useDispatch();
const navigate = useNavigate();

const handleSubmit = (e) => {
e.preventDefault();
//? kullanici bilgileri ile state'i guncelleme istegi
dispatch(setUser({ email, password }));
setEmail("");
setPassword("");
navigate("/");
};

return (




Sign in


setEmail(e.target.value)}
/>
setPassword(e.target.value)}
/>


Sign In



{"Copyright © "}

Clarusway
{new Date().getFullYear()}
{"."}


);
}
```

- PrivateRouter.jsx (useSelector() ile state i kullanacagimiz componentte cagirma)

```jsx
import { useSelector } from "react-redux";
import { Navigate, Outlet } from "react-router-dom";

const PrivateRouter = () => {
// const user = true
//? consuming
const user = useSelector((state) => state.auth.user);

return user?.email ? : ;
};

export default PrivateRouter;
```

- Navbar.jsx

```jsx
import * as React from "react";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { clearUser } from "../features/authSlice";

export default function Navbar() {
const navigate = useNavigate();
const dispatch = useDispatch();
const { user } = useSelector((state) => state.auth);

const handleLogout = () => {
dispatch(clearUser());
};

return (



navigate("/")}
>
Clarusway News

{user?.email && (

Logout

)}
{!user?.email && Login}



);
}
```

- News.jsx

```jsx
import Box from "@mui/material/Box";
import Card from "@mui/material/Card";
import CardActions from "@mui/material/CardActions";
import CardContent from "@mui/material/CardContent";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { CardMedia } from "@mui/material";
import { clearNews, getNews } from "../features/newsSlice";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import loadingGif from "../assets/loading.gif";

const News = () => {
const dispatch = useDispatch();
const { news, error, loading } = useSelector((state) => state.api);

useEffect(() => {
dispatch(getNews());

//? news componenti DOM tree'den kaldirilinca state'deki bilgileri temizle
return () => {
dispatch(clearNews());
};
}, []);

console.log(error);
return (
<>

NEWS

{loading && (



)}

{error && (

News can not be fetched

)}

{news?.map((item, index) => (




{item?.title}


{item?.content}



Share

Detail



))}

>
);
};

export default News;
```