React Tutorial
Estimated reading: 4 minutes 291 views

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 or axios
  • useEffect with useState or useReducer
  • 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?

Featurefetch (built-in)axios (library)
DefaultIncluded in browsersRequires installation
JSON parsingManual .json()Automatic
Error handlingManualBuilt-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 :
Share

🌐 React API Integration & Data Fetching

Or Copy Link

CONTENTS
Scroll to Top