π React API Integration & Data Fetching β Best Practices & Patterns (2025 Guide)
π§² Introduction β Why API Integration Matters in React
Modern React.js applications often rely on external APIs to retrieve and display dataβfrom user profiles and products to real-time dashboards and search results. Effective API integration is crucial for performance, UX, and data consistency.
React offers multiple ways to fetch data, including:
- π Native
fetch
API oraxios
- β
useEffect
withuseState
oruseReducer
- π οΈ Libraries like SWR, React Query, and RTK Query
π― In this guide, youβll learn:
- How to fetch data in React using built-in hooks
- Handle loading, error, and success states
- Compare common API libraries
- Structure reusable data-fetching logic
βοΈ 1. Basic API Fetching with useEffect
& fetch
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => {
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
})
.then(data => setUsers(data))
.catch(setError)
.finally(() => setLoading(false));
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
β
Handles loading and error
β
Uses useEffect
for side effect
π Best for simple API needs
π¦ 2. Axios vs Fetch β Which to Use?
Feature | fetch (built-in) | axios (library) |
---|---|---|
Default | Included in browsers | Requires installation |
JSON parsing | Manual .json() | Automatic |
Error handling | Manual | Built-in |
Interceptors | β No | β Yes |
Cancel requests | β³οΈ With AbortController | β Axios Cancel Token |
npm install axios
π 3. Custom Hook for Reusable Data Fetching
β
useFetch.js
import { useState, useEffect } from 'react';
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') setError(err);
})
.finally(() => setLoading(false));
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
π Abstracts loading, cleanup, and cancellation logic
β
Great for reusability
π 4. React Query β Powerful Async State
npm install @tanstack/react-query
β Setup:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
β Usage:
import { useQuery } from '@tanstack/react-query';
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json())
});
β
Built-in caching, refetching, retries, and pagination
β
Works well with mutations (useMutation
)
β
Ideal for dashboards and large apps
π οΈ 5. RTK Query β Redux Toolkitβs Data Layer
npm install @reduxjs/toolkit react-redux
β API Slice Example:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const userApi = createApi({
reducerPath: 'userApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => 'users',
}),
}),
});
export const { useGetUsersQuery } = userApi;
β Usage in Component:
const { data, isLoading, error } = useGetUsersQuery();
β
Pairs with Redux store
β
Auto-generates hooks
β
Built-in caching, polling, and optimistic updates
π Best Practices
β
Use AbortController
for manual fetch cleanup
β
Handle loading and error states gracefully
β
Use React Query or RTK Query for data-heavy apps
β
Avoid fetching in render logic (use useEffect
instead)
β
Cache data when appropriate to reduce API calls
π Summary β Recap & Next Steps
Data fetching is a critical part of modern React applications. Whether you choose to use fetch
, axios
, or advanced tools like React Query and RTK Query, the key is to handle loading, error, and cleanup properly.
π Key Takeaways:
- Use
useEffect
for basic fetching - Use custom hooks to DRY your code
- Axios simplifies requests and adds more features
- React Query and RTK Query manage async state like a pro
- Always manage cleanup and dependencies carefully
βοΈ Real-World Relevance:
Used in apps like GitHub, Notion, Trello, and Stripe to fetch user data, paginate APIs, and sync data in real time.
β FAQ Section
β Should I use fetch
or axios
?
β
Use fetch
for basic needs, and axios
for more complex setups (interceptors, token injection, error handling).
β Whatβs the benefit of React Query over useEffect
+ fetch
?
β
React Query handles caching, retries, background refetching, and stale data automatically.
β Is useEffect
the best place to fetch data?
β
Yes, for simple APIs. For complex data flows, prefer libraries like React Query or RTK Query.
β Do I need Redux if I use React Query?
β Not necessarily. React Query can replace Redux for many async use cases.
β Can I cancel API requests in React?
β
Yes, using AbortController
with fetch or CancelToken
in Axios.
Share Now :