Building Authentication and API Integration in React Native with Redux Toolkit

in blurt •  2 years ago 

Introduction:
Today I will explore the implementation of authentication and API integration in a React Native application using the Redux Toolkit. We will walk through the code step by step, explaining each part

Setting Up the Initial State:
We start by importing the necessary dependencies such as AsyncStorage for storing data, and createAsyncThunk and createSlice from Redux Toolkit for asynchronous operations and state management, respectively. We also import some constants and helper functions.

src
We define an interface called authSate to represent the initial state of our authentication slice. It includes properties like logout, userEmail, loadTokenVerify, token, refreshToken, tokenError, permissions, currentToken, leads, calledList, and localStorageCallList. These properties will hold different pieces of authentication and API-related data.

Next, we initialize the initialState object with default values for each property. These values will be used to set the initial state of the authentication slice.

Creating Async Thunks for API Calls:
We define two async thunks using createAsyncThunk. The first thunk, fetchLogout, is responsible for making a logout API call. It takes a token parameter and sends a GET request to the logout endpoint using the provided token.

The second thunk, fetchToken, fetches token information from an API endpoint. It takes a token parameter and sends a POST request to the tokeninfo endpoint with the provided token.

Creating the Authentication Slice:
Using createSlice, we define the authSlice slice. It consists of a name (authSlice), the initialState, reducers, and extraReducers.

In the reducers section, we define several action creators such as reset, setUserEmail, setToken, removeCookies, setLoadTokenVerify, setLeadsManager, setCalledList, and setLocalStorageCallList. These action creators are used to modify the state properties in response to specific actions.

The extraReducers section handles the additional reducers generated by the async thunks. For example, when fetchLogout.fulfilled is dispatched, it updates the logout and userEmail properties in the state based on the API response.

src

Exporting the Slice and Action Creators:
We export the authSlice.reducer as the default export of the module. This reducer will be combined with other reducers in the application.

Additionally, we export all the action creators defined in the reducers section, such as setUserEmail, removeCookies, setLoadTokenVerify, setLeadsManager, setToken, reset, setCalledList, and setLocalStorageCallList. These action creators can be dispatched to trigger state updates.

Conclusion:
In this blog post, we explored the code that implements authentication and API integration in a React Native application using Redux Toolkit. We discussed the initial state, async thunks for API calls, the authentication slice, and the associated action creators.

import AsyncStorage from '@react-native-async-storage/async-storage';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

import { BASE_URL, collegeId, localStorageKeyName } from '../../Constants/API';
import { ApiCallHeaderAndBody } from '../../Helper Function/ApiCallHeaderAndBody';

// Interface representing the initial state
interface authSate {
  // Properties related to authentication
  logout: boolean;
  userEmail: { userId: string; authenticated: boolean };
  loadTokenVerify: boolean;
  token: any;
  refreshToken: any;
  tokenError: string;
  permissions: {};
  currentToken: any;

  // Properties related to data storage
  leads: [];
  calledList: [];
  localStorageCallList: {
    type: string[];
    mobile_numbers: string[];
    call_started_datetimes: string[];
    call_durations: string[];
  };
}

// Initial state for the authentication slice
const initialState: authSate = {
  logout: false,
  userEmail: { userId: '', authenticated: false },
  loadTokenVerify: false,
  token: '',
  refreshToken: '',
  tokenError: '',
  permissions: {},
  currentToken: '',
  leads: [],
  calledList: [],
  localStorageCallList: {
    type: [],
    mobile_numbers: [],
    call_started_datetimes: [],
    call_durations: [],
  },
};

// Fetching logout API
export const fetchLogout = createAsyncThunk('/logout', async (token: any) => {
  const response = await fetch(
    `${BASE_URL}student_user_crud/logout/?college_id=${collegeId}`,
    ApiCallHeaderAndBody(token, 'GET', []),
  ).then(res => res.json());
  return response;
});

// Fetching token info API
export const fetchToken = createAsyncThunk(
  '/fetchToken',
  async (token: any) => {
    const response = await fetch(
      `${BASE_URL}oauth/tokeninfo?token=${token}&college_id=${collegeId}`,
      {
        method: 'POST',
        headers: {
          accept: 'application/json',
        },
      },
    ).then(res => res.json());
    return response;
  },
);

// Creating the authSlice using createSlice
export const authSlice = createSlice({
  name: 'authSlice',
  initialState,
  reducers: {
    // Resetting the state
    reset: state => {
      state.logout = false;
      state.userEmail = { userId: '', authenticated: false };
      state.loadTokenVerify = false;
      state.token = '';
      state.tokenError = '';
      state.permissions = {};
      state.currentToken = '';
      state.leads = [];
      state.calledList = [];
    },
    // Setting the user email
    setUserEmail: (state, action) => {
      state.userEmail = action.payload;
    },
    // Setting the access token and refresh token
    setToken: (state, action) => {
      state.currentToken = action.payload.access_token;
      state.refreshToken = action.payload.refresh_token;
    },
    // Removing cookies and clearing token-related data
    removeCookies: state => {
      state.token = '';
      state.userEmail = { userId: '', authenticated: false };
      state.loadTokenVerify = false;
      state.currentToken = '';
      AsyncStorage.removeItem(`${localStorageKeyName}jwtTokenGTCRM`);
    },
    // Setting the loading state for token verification
    setLoadTokenVerify: (state, action) => {
      state.loadTokenVerify = action.payload;
    },
    // Setting the leads data
    setLeadsManager: (state, action) => {
      state.leads = action.payload;
    },
    // Setting the called list data
    setCalledList: (state, action) => {
      state.calledList = action.payload;
    },
    // Setting the local storage call list
    setLocalStorageCallList: (state, action) => {
      state.localStorageCallList = action.payload;
    },
  },
  extraReducers: builder => {
    // Handling the logout API response
    builder.addCase(fetchLogout.fulfilled, state => {
      state.userEmail = { userId: '', authenticated: false };
      state.logout = true;
    });
    builder.addCase(fetchLogout.pending, state => {
      state.logout = false;
    });
    builder.addCase(fetchLogout.rejected, state => {
      state.logout = false;
    });

    // Handling the token info API response
    builder.addCase(fetchToken.fulfilled, (state, action) => {
      state.token = action.payload;
    });
    builder.addCase(fetchToken.rejected, state => {
      state.token = { detail: 'network error' };
      state.currentToken = '';
    });
  },
});

// Exporting the action creators
export const {
  setUserEmail,
  removeCookies,
  setLoadTokenVerify,
  setLeadsManager,
  setToken,
  reset,
  setCalledList,
  setLocalStorageCallList,
} = authSlice.actions;

export default authSlice.reducer;
Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE BLURT!