Building a Structured API Call in React Native with Axios and Redux
When building React Native apps, it’s important to handle state management efficiently, especially when making API calls and dealing with asynchronous data. Using Redux in conjunction with Axios allows you to organize your API interactions in a scalable, maintainable way. In this guide, we’ll take the previous setup of structured API calls and add Redux to manage the global state.
1. Setting Up Redux in React Native
First, install the necessary dependencies:
npm install redux react-redux @reduxjs/toolkit axios
We’ll use Redux Toolkit for efficient Redux setup.
2. Organizing the Project Structure
Here's an updated structure that includes Redux:
src/
│
├── api/
│ └── AxiosService.ts
│
├── models/
│ └── User.ts
│
├── services/
│ └── UserService.ts
│
├── store/
│ ├── userSlice.ts
│ └── store.ts
│
└── App.tsx
3. Setting Up Axios for API Calls
First, let’s set up AxiosService.js as before to manage the HTTP requests.
AxiosService.js:
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
class AxiosService {
private instance: AxiosInstance;
constructor() {
this.instance = axios.create({
baseURL: 'https://api.example.com/', // Set your base URL here
timeout: 5000,
});
// Handle the response globally
this.instance.interceptors.response.use(
(response: AxiosResponse) => response,
(error) => Promise.reject(error)
);
}
// GET request
public get<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.instance.get(url, config);
}
// POST request
public post<T>(url: string, data: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.instance.post(url, data, config);
}
}
const axiosService = new AxiosService();
export default axiosService;
4. Creating the Model Class
Our User.js model class remains the same:
export default class User {
public id: number;
public name: string;
public email: string;
constructor(id: number, name: string, email: string) {
this.id = id;
this.name = name;
this.email = email;
}
// Static method to create a User object from the API response
public static fromApi(data: any): User {
return new User(data.id, data.name, data.email);
}
}
5. Creating the User Service
The service layer will call the Axios service and map the response to the User model.
UserService.ts:
领英推荐
import axiosService from '../api/AxiosService';
import User from '../models/User';
class UserService {
// Fetch a list of users from the API
public static async getUsers(): Promise<User[]> {
const response = await axiosService.get<User[]>('/users');
return response.data.map((user) => User.fromApi(user));
}
// Fetch a single user by ID
public static async getUserById(userId: number): Promise<User> {
const response = await axiosService.get<User>(`/users/${userId}`);
return User.fromApi(response.data);
}
// Create a new user
public static async createUser(userData: Partial<User>): Promise<User> {
const response = await axiosService.post<User>('/users', userData);
return User.fromApi(response.data);
}
}
export default UserService;
6. Setting Up Redux Store and Slice
We will now configure Redux to manage the global state of our users. Redux Toolkit simplifies the setup.
userSlice.ts:
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import UserService from '../services/UserService';
import User from '../models/User';
interface UserState {
users: User[];
loading: boolean;
error: string | null;
}
// Initial state
const initialState: UserState = {
users: [],
loading: false,
error: null,
};
// Fetch users asynchronously using Redux Thunk
export const fetchUsers = createAsyncThunk('users/fetchUsers', async () => {
const users = await UserService.getUsers();
return users;
});
// User slice
const userSlice = createSlice({
name: 'users',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUsers.pending, (state) => {
state.loading = true;
})
.addCase(fetchUsers.fulfilled, (state, action: PayloadAction<User[]>) => {
state.loading = false;
state.users = action.payload;
})
.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message || 'Failed to fetch users';
});
},
});
export default userSlice.reducer;
store.ts:
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
// Configure the Redux store
export const store = configureStore({
reducer: {
users: userReducer,
},
});
// Define the RootState type for use with TypeScript
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
This sets up the Redux store and defines the types used with TypeScript.
7. Connecting Redux with the React Native Component
In the App.tsx component, we will use the useSelector and useDispatch hooks from React Redux to fetch and display the user data.
App.tsx:
import React, { useEffect } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from './src/store/userSlice';
import { RootState } from './src/store/store';
import { Provider } from 'react-redux';
import { store } from './src/store/store';
const UserList: React.FC = () => {
const dispatch = useDispatch();
const { users, loading, error } = useSelector((state: RootState) => state.users);
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
return (
<View style={styles.container}>
<Text style={styles.header}>User List</Text>
{loading ? (
<Text>Loading...</Text>
) : error ? (
<Text>Error: {error}</Text>
) : (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<Text style={styles.user}>{item.name} - {item.email}</Text>
)}
/>
)}
</View>
);
};
const App: React.FC = () => {
return (
<Provider store={store}>
<UserList />
</Provider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center',
},
header: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 10,
},
user: {
fontSize: 18,
marginVertical: 5,
},
});
export default App;
8. Summary
In this example, we:
By structuring your React Native app with Axios, Redux, and TypeScript, you ensure that your code is scalable, maintainable, and easy to understand.
Hashtags for the Article:
#ReactNative #TypeScript #Axios #ReduxToolkit #APICalls #MobileAppDevelopment #JavaScript #StateManagement #CleanCode #FrontendDevelopment