Mehedi Hassan Piash [Sr. Software Engineer]

May 27, 2022

Modern redux architecture with redux-saga and redux-toolkit

May 27, 2022 Posted by Piash , No comments

 Redux is the most popular library for state management in react and react-native app development. On the other redux-saga is a middleware library used to allow a Redux store to interact with resources outside of itself asynchronously. So it's almost common to use redux-saga with redux.

import {createSlice} from '@reduxjs/toolkit'

const movieDetailState = createSlice({
name: 'movieDetail', initialState: {
movieDetail: {}, isLoading: false,
}, reducers: {
getMovieDetail: (state, action) => {
state.isLoading = true
}, movieDetailSuccess: (state, action) => {
state.movieDetail = action.payload;
state.isLoading = false
}, movieDetailFailure: (state) => {
state.isLoading = false
}
}
});
export const {getMovieDetail, movieDetailSuccess, movieDetailFailure} = movieDetailState.actions;
export default movieDetailState.reducer
import {configureStore} from '@reduxjs/toolkit'
import combineReducers from './reducer';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './sagas';
import logger from 'redux-logger';

const sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];

const configurationAppStore = () => {
const store = configureStore({
reducer: combineReducers, middleware: [...middleware, logger], devTools: process.env.NODE_ENV === 'development'
})
sagaMiddleware.run(rootSaga);
return store
}
export default configurationAppStore
import {takeEvery, call, put} from 'redux-saga/effects';
import AxiosService from '../../../networks/AxiosService';
import {ApiUrls} from '../../../networks/ApiUrls';
import {movieDetailSuccess, movieDetailFailure, getMovieDetail} from './../../reducer/moviedetail'
function* movieDetailApi(action) {
try {
const response = yield call(AxiosService.getServiceData, ApiUrls.MOVIE_DETAIL(action.payload.movieId), {});
const result = response.data;
yield put(movieDetailSuccess(result));
} catch (error) {
yield put(movieDetailFailure());
}
}
const combineSagas = [takeEvery(takeEvery(getMovieDetail.type, movieDetailApi)];
export default combineSagas
import {all} from 'redux-saga/effects';
import combineSagas from "./movielist";

export default function* rootSaga() {
yield all([...combineSagas]);
}
import React from 'react';
import configureStore from './src/redux';
import {Provider} from 'react-redux';
import Navigation from './src/navigation/AppNavigation';

const store = configureStore();
const App = () => {
return (
<Provider store={store}>
<Navigation />
</Provider>
);
};

export default App;
import React, {useEffect} from 'react';
import {useSelector, useDispatch} from 'react-redux';
import Loading from '../../components/loading/Loading';
import styles from './MovieDetailStyle'
import {FlatList, Image, Text, TouchableOpacity, View, ScrollView} from "react-native";
import {Constants} from "../../appconstants/AppConstants";
import {getMovieDetail} from './../../redux/reducer/moviedetail';

const MovieDetail = ({navigation, route}) => {
const {movieId} = route.params
//communicate with redux
const {isLoading, movieDetail} = useSelector(state => state.movieDetailReducer);

// Api call
useEffect(() => {
dispatch(getMovieDetail({movieId}))
}, [])

// main view with loading while api call is going on
return isLoading ? <Loading/> : (<ScrollView style={styles.mainView}>
<Image
style={styles.imageView}
source={{
uri: `${Constants.IMAGE_URL}${movieDetail?.poster_path}`,
}}/>
<View style={styles.secondContainer}>
<Text style={styles.title}>{movieDetail.title}</Text>
<View style={styles.thirdContainer}>
<View style={styles.fourthContainer}>
<Text style={styles.infoTitleData}>{movieDetail.original_language}</Text>
<Text style={styles.infoTitle}>Language</Text>
</View>
<View style={styles.fourthContainer}>
<Text style={styles.infoTitleData}>{movieDetail.vote_average}</Text>
<Text style={styles.infoTitle}>Rating</Text>
</View>
<View style={styles.fourthContainer}>
<Text style={styles.infoTitleData}>{movieDetail.runtime} min</Text>
<Text style={styles.infoTitle}>Duration</Text>
</View>
<View style={styles.fourthContainer}>
<Text style={styles.infoTitleData}>{movieDetail.release_date}</Text>
<Text style={styles.infoTitle}>Release Date</Text>
</View>
</View>
<Text style={styles.description}>Description</Text>
<Text>{movieDetail.overview}</Text>
<Text style={styles.description}>Similar</Text>
</View>
</ScrollView>)
}
export default MovieDetail