Mastering Data Fetching in Next.js With Fetch, Axios, and SWR
In the world of web development, fetching data efficiently is crucial for building responsive, user-friendly applications. In Next.js, there are multiple ways to fetch data, each with its own set of advantages and drawbacks. In this guide, we’ll dive deep into three popular methods: fetch
, axios
, and SWR
, discussing when and how to use each, along with their pros, cons, and best practices.
Fetching Data With Fetch
The fetch
API is a native JavaScript function that provides a way to make HTTP requests. It’s a low-level API with a minimalistic design, making it a great choice for straightforward tasks.
Pros:
- Native Support: Built into JavaScript, no need for additional libraries.
- Flexibility: Offers granular control over HTTP requests, making it suitable for complex requests.
- Lightweight: No added dependencies, reducing the overall bundle size.
Cons:
- Manual Parsing:
fetch
returns aResponse
object, and you need to call.json()
to parse the response body into a JavaScript object. - No Automatic Error Handling:
fetch
only rejects the promise if there’s a network error. HTTP errors (like 404 or 500) don’t automatically reject the promise, so you must manually checkresponse.ok
. - Verbose Configuration: Setting up headers, request bodies, and handling different HTTP methods can be verbose and repetitive.
Best Practices:
- Use
fetch
for Server-Side Data Fetching: Sincefetch
is a native API, it's a good choice for server-side operations, especially in API routes or withingetServerSideProps
orgetStaticProps
. - Check
response.ok
: Always checkresponse.ok
to handle HTTP errors properly. - Consider Performance: Since
fetch
doesn't have built-in features like automatic retries or interceptors, consider these limitations for highly complex requests.
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const apiKey = process.env.SECURE_API_KEY; // Use environment variable for sensitive data
try {
const response = await fetch("https://reqres.in/api/users?page=2", {
headers: {
Authorization: `Bearer ${apiKey}`,
},
});
if (!response.ok) {
throw new Error(`Failed to fetch data: ${response.statusText}`);
}
const data = await response.json();
res.status(200).json(data);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
}
Fetching Data With Axios
axios
is a popular third-party HTTP client library that simplifies the process of making HTTP requests. It offers additional features and a more intuitive API compared to fetch
.
Pros:
- Automatic JSON Parsing:
axios
automatically parses JSON responses, so you don't need to call.json()
. - Automatic Error Handling:
axios
automatically rejects the promise for HTTP errors (non-2xx responses), simplifying error handling. - Simpler Configuration: Provides a more intuitive API for setting up headers, query parameters, and other request options.
- Interceptors:
axios
supports request and response interceptors, allowing you to modify requests or responses globally.
Cons:
- Additional Dependency: Requires installation of the
axios
library, adding to your project's bundle size. - Slight Overhead: While minimal,
axios
introduces additional overhead compared to the nativefetch
API.
Best Practices:
- Use
axios
for Client-Side and Server-Side Requests: Its simplicity and features makeaxios
a good choice for both front-end and back-end data fetching. - Leverage Interceptors: Use interceptors for tasks like adding authentication tokens to requests or logging responses and errors.
- Automatic Error Handling: Take advantage of
axios
's automatic rejection of non-2xx responses to reduce the need for manual error checks.
import { useEffect, useState } from "react";
import axios from "axios";
interface Resource {
id: number;
name: string;
year: number;
color: string;
pantone_value: string;
}
const AxiosExample = () => {
const [data, setData] = useState<Resource[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get("https://reqres.in/api/unknown");
setData(response.data.data);
} catch (err) {
setError((err as Error).message);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Axios Example</h1>
<ul>
{data.map((resource) => (
<li key={resource.id} style={{ backgroundColor: resource.color }}>
{resource.name} ({resource.year}) - Pantone:{" "}
{resource.pantone_value}
</li>
))}
</ul>
</div>
);
};
export default AxiosExample;
Fetching Data With SWR
SWR
(stale-while-revalidate) is a React hook library for data fetching developed by Vercel, the team behind Next.js. It’s designed for client-side data fetching with caching and revalidation features.
Pros:
- Caching:
SWR
automatically caches the data from API requests and reuses the cache on subsequent renders or requests. - Revalidation: Automatically revalidates data in the background, ensuring the UI is always up-to-date.
- Optimistic Updates: Allows the UI to update optimistically before the API call is confirmed, providing a smoother user experience.
- Built-in Pagination and Infinite Loading:
SWR
simplifies implementing pagination and infinite loading, which can be complex withfetch
oraxios
. - Automatic Retry:
SWR
can automatically retry failed requests, reducing the need for custom retry logic.
Cons:
- Client-Side Only:
SWR
is designed to run on the client side, so it’s not suitable for server-side rendering scenarios where you need data before rendering the page. - Additional Dependency: Like
axios
,SWR
is a third-party library, adding to your project's dependencies.
Best Practices:
- Use
SWR
for Client-Side Fetching: Perfect for front-end scenarios where you need features like caching, revalidation, and optimistic updates. - Handle Dynamic Content:
SWR
excels in scenarios with frequently changing or user-specific data. - Combine with API Routes: Use
SWR
in conjunction with Next.js API routes for secure and efficient data fetching.
import Image from "next/image";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
const SecureFetchExample = () => {
const { data, error, isLoading } = useSWR("/api/secure-data", fetcher);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>Secure Fetch Example with SWR</h1>
<ul>
{data.data.map((resource: any) => (
<li key={resource.id}>
<Image
src={resource.avatar}
width={50}
height={50}
alt={resource.first_name}
/>
{resource.email} ({resource.id}) - Pantone: {resource.pantone_value}
</li>
))}
</ul>
</div>
);
};
export default SecureFetchExample;
When to Use Each Method
- Server-Side with
fetch
: Use for secure API calls in API routes or when fetching dynamic data that needs to be up-to-date on every request (getServerSideProps
). - Server-Side with
axios
: Ideal for more complex API calls with easier configuration and automatic error handling, used in bothgetServerSideProps
andgetStaticProps
. - Client-Side with
SWR
: Best for fetching data on the front end with caching, revalidation, and real-time updates. Ideal for user-specific or frequently changing data.
Best Practices for Server-Side vs. Client-Side Data Fetching
- Server-Side Fetching:
- Use
getServerSideProps
for Dynamic Content: Fetch data on each request for content that needs to be up-to-date. - Use
getStaticProps
for Static Content: Ideal for content that doesn't change often, improving performance with static generation. - Secure API Calls: Use API routes with
fetch
to keep sensitive data like API keys secure.
- Use
- Client-Side Fetching:
- Leverage
SWR
for Dynamic or User-Specific Data: UseSWR
to handle client-side data that needs to be revalidated or cached. - Handle Real-Time Updates: Use
SWR
for scenarios where the data changes frequently and you need to keep the UI updated.
- Leverage
Final Thoughts on Data Fetching in Next.js
Understanding when to use fetch
, axios
, and SWR
in your Next.js applications can significantly enhance both the performance and user experience of your projects. By following the best practices outlined in this guide, you can ensure that your data fetching strategy is secure, efficient, and perfectly suited to your application's needs.
References
- SWR Documentation: SWR Documentation.
- Next.js Fetch API Reference: Next.js Fetch API Reference.