In this tutorial, you’ll learn how to integrate Redux-Saga into your React Native app and manage asynchronous side effects such as API requests using sagas. By the end of today’s lesson, you’ll have replaced Redux Thunk with Redux-Saga for managing asynchronous actions in your app.
What You Will Learn Today:
- Installing and setting up Redux-Saga
- Creating sagas to handle side effects
- Dispatching actions with sagas
- Using
takeEvery
andcall
effects in Redux-Saga - Testing Redux-Saga with an API call
Step 1: Installing Redux-Saga
To begin using Redux-Saga, you’ll need to install the redux-saga package and set it up in your Redux store.
- Install redux-saga:
npm install redux-saga
- Modify your Redux store to configure Redux-Saga. Open
store/store.js
and update it as follows:
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas'; // We will create this next
// Create the saga middleware
const sagaMiddleware = createSagaMiddleware();
// Create the Redux store with saga middleware
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
// Run the root saga
sagaMiddleware.run(rootSaga);
export default store;
Explanation:
- createSagaMiddleware(): Initializes the Redux-Saga middleware, which will handle running your sagas.
- sagaMiddleware.run(rootSaga): Runs the root saga where all your individual sagas will be combined.
- applyMiddleware(sagaMiddleware): Adds the Redux-Saga middleware to your Redux store.
Step 2: Creating Sagas to Handle Side Effects
Let’s now create sagas that will handle the side effects, such as fetching data from an API. Sagas are generator functions that yield effects to describe what should happen (e.g., making an API call or dispatching an action).
- Inside the
store
folder, create a new folder calledsagas
, and inside it, create a file calledpostSagas.js
:
mkdir store/sagas
touch store/sagas/postSagas.js
- Open
postSagas.js
and create the saga to fetch posts:
import { call, put, takeEvery } from 'redux-saga/effects';
// Worker saga: makes the API call when the watcher saga sees the action
function* fetchPostsSaga() {
try {
const response = yield call(fetch, 'https://jsonplaceholder.typicode.com/posts');
const data = yield response.json();
yield put({ type: 'FETCH_POSTS_SUCCESS', payload: data });
} catch (error) {
yield put({ type: 'FETCH_POSTS_FAILURE', error: error.message });
}
}
// Watcher saga: watches for actions dispatched to the store and starts the worker saga
export function* watchFetchPosts() {
yield takeEvery('FETCH_POSTS_REQUEST', fetchPostsSaga);
}
Explanation:
- fetchPostsSaga: This is the worker saga that performs the actual API request when triggered. It uses the
call
effect to call thefetch
function and theput
effect to dispatch either a success or failure action. - watchFetchPosts: This is the watcher saga that listens for
FETCH_POSTS_REQUEST
actions. When such an action is dispatched, it runs thefetchPostsSaga
. - call(): Effect that makes the API call in a saga.
- put(): Effect that dispatches an action in a saga.
- takeEvery(): Watches for every occurrence of a specified action and runs the corresponding worker saga.
Combining Sagas
We’ll now combine the sagas into a rootSaga that the Redux store will use.
- Inside the
sagas
folder, create a file calledindex.js
:
touch store/sagas/index.js
- Open
index.js
and combine the sagas:
import { all } from 'redux-saga/effects';
import { watchFetchPosts } from './postSagas';
// Root saga: combines all the individual sagas into one
export default function* rootSaga() {
yield all([watchFetchPosts()]);
}
Explanation:
- all(): Effect that runs multiple sagas concurrently. In this case, it combines the watchFetchPosts saga with any other sagas you may add in the future.
Step 3: Dispatching Actions with Sagas
Let’s now dispatch the FETCH_POSTS_REQUEST
action from a component to trigger the saga and fetch posts from the API.
- Open
Posts.js
and modify it to dispatch theFETCH_POSTS_REQUEST
action:
import React, { useEffect } from 'react';
import { View, Text, ActivityIndicator, FlatList } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
export default function Posts() {
const dispatch = useDispatch();
const { posts, loading, error } = useSelector((state) => state.posts);
useEffect(() => {
dispatch({ type: 'FETCH_POSTS_REQUEST' }); // Dispatch the saga action
}, [dispatch]);
if (loading) {
return <ActivityIndicator size="large" color="#0000ff" />;
}
if (error) {
return (
<View>
<Text>Error: {error}</Text>
</View>
);
}
return (
<FlatList
data={posts}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={{ padding: 10 }}>
<Text style={{ fontWeight: 'bold' }}>{item.title}</Text>
<Text>{item.body}</Text>
</View>
)}
/>
);
}
Explanation:
- We replaced the thunk-based action dispatch with the saga-based action by dispatching
{ type: 'FETCH_POSTS_REQUEST' }
. This triggers the watchFetchPosts saga, which in turn runs fetchPostsSaga to fetch the posts.
Step 4: Testing Redux-Saga with an API Call
With Redux-Saga now set up, let’s test the asynchronous action flow by running the app and fetching posts from the API.
- Run your app:
npm start
- You should see the loading spinner while the data is being fetched. Once the data is fetched successfully, the list of posts should be displayed. If there’s an error, it will be shown on the screen.
Step 5: Recap and Summary
In today’s tutorial, you learned how to manage asynchronous side effects using Redux-Saga in a React Native app. Here’s a quick summary of what you’ve done:
- Installed and set up Redux-Saga in your Redux store.
- Created worker and watcher sagas to handle asynchronous operations.
- Used effects like call, put, and takeEvery to manage side effects in Redux-Saga.
- Replaced Redux Thunk with Redux-Saga to fetch posts from an API and update the Redux state.
- Tested Redux-Saga with API requests and displayed the fetched data in your app.
With Redux-Saga in place, your app can now handle complex side effects like API requests in a more powerful and scalable way.
Next Up: Day 5 – Implementing Authentication with JWT in React Native
In Day 5, we’ll implement authentication with JWT (JSON Web Tokens) in your React Native app. You’ll learn how to handle user login, secure routes, and store authentication tokens securely.
Stay tuned for more advanced features tomorrow!