Part 42: Optimizing Client-Side Data Fetching with Next.js API Routes
[Pages] Data Fetching

In our journey through data fetching strategies in Next.js, we've previously set up an API route to fetch products from a CMS while stripping out unnecessary fields. Now, let's explore how to utilize this API route from the client side, creating a more efficient data flow.
Introducing Option 2b: Client-Side Fetching via API Routes
While our previous setup, labeled as "Option 2a", involved fetching product data directly from the CMS on the client side, "Option 2b" refines this by fetching data from an internal API route. This approach brings several advantages, including reduced data size and increased security.
Setting Up the Client-Side Fetch
Let's create a new page to implement this strategy. The page will fetch data from our /api/products endpoint instead of directly querying the CMS.
// pages/index-2b.js
// Option 2b: fetch products on the client side (in useEffect)
// from an internal API route
import Head from 'next/head';
import { useEffect, useState } from 'react';
import Title from '../components/Title';
function HomePage() {
const [products, setProducts] = useState([]);
useEffect(() => {
(async () => {
const response = await fetch('/api/products');
const products = await response.json();
setProducts(products);
})();
}, []);
console.log('[HomePage] render:', products);
return (
<>
<Head>
<title>Next Shop</title>
</Head>
<main className="px-6 py-4">
<Title>Next Shop</Title>
<ul>
{products.map((product) => (
<li key={product.id}>
{product.title}
</li>
))}
</ul>
</main>
</>
);
}
export default HomePage;How It Works
Fetching Data: Instead of calling the CMS directly, we fetch data from
/api/products. This API route is hosted on the same server, so there’s no need to specify the host and port.Handling Asynchronous Calls: Since
fetchis asynchronous, we wrap it in an immediately invoked async function withinuseEffect, allowing us to useawait.State Management: Once the data is fetched and parsed as JSON, it's stored in a state variable using
setProducts.Rendering Products: The component then maps over the
productsarray, rendering each product'stitle.
Observing the Benefits
Upon loading the new page, you'll notice the server logs indicate that the /api/products handler is invoked each time the page is rendered. Inspecting network requests reveals that the API route is queried on localhost at port 3000, and the response data contains only the necessary fields.
Data Size Comparison
Option 2b (Internal API Route): The response size is significantly reduced to 192 bytes, as indicated by the
Content-Lengthheader.Option 2a (Direct CMS Call): In comparison, direct calls to the CMS resulted in a response size of 9,363 bytes.
This reduction in data size showcases the efficiency of fetching data through an API route, highlighting the potential performance benefits and improved security by abstracting the CMS behind a server-side endpoint.
Conclusion
By adopting "Option 2b," we leverage Next.js API routes to optimize client-side data fetching. This approach not only minimizes the data payload but also enhances application security by shielding the CMS API behind the server. While setting up API routes introduces some additional work, the benefits in performance and data management are well worth the effort.
In our next discussion, we'll review all data fetching options in Next.js and determine the best approach for various scenarios. This comprehensive understanding will enable you to choose the most effective strategy for your specific application needs.
Last updated