Effortlessly Manage Data Fetching in Next.js with useQuery
Introduction
We've all been there—stuck in the weeds of data fetching, managing state, and handling errors, all while trying to build a sleek Next.js app. It can feel like a never-ending battle. But what if I told you there's a way to make this process almost effortless? Enter useQuery
from React Query. This hook takes the headache out of data fetching, so you can focus on what you love: crafting amazing user experiences. In this blog post, I'll show you how useQuery
can transform your Next.js projects, making your data fetching smooth, efficient, and virtually hassle-free.
What is useQuery
?
useQuery
is a hook from the React Query library designed to handle server state in your applications. It provides an elegant solution for fetching data, caching it, and keeping your UI in sync with the server state. By using useQuery
, you can focus more on building your application and less on managing the intricacies of data fetching.
Before useQuery
Let's start by looking at a typical approach to data fetching in a Next.js component, without using useQuery
.
import { useEffect, useState } from 'react';
const AdviceGenerator = () => {
const [advice, setAdvice] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const fetchAdvice = async () => {
setIsLoading(true);
try {
const response = await fetch('https://api.adviceslip.com/advice');
const data = await response.json();
setAdvice(data.slip.advice);
} catch (err) {
setError(err);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchAdvice();
}, []);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>An error occurred</div>;
return (
<div>
<h1>{advice}</h1>
<button onClick={fetchAdvice}>Get New Advice</button>
</div>
);
}
export default AdviceGenerator;
Here, we have to manage the loading state, error state, and data fetching manually using useState
and useEffect
. It works, but it can get messy and repetitive.
After useQuery
Now, let's see how useQuery
can simplify this process.
import { useQuery, useQueryClient } from '@tanstack/react-query';
const fetchAdvice = async () => {
const response = await fetch('https://api.adviceslip.com/advice');
const data = await response.json();
return data.slip.advice;
};
const AdviceGenerator = () => {
const queryClient = useQueryClient();
const { data: advice, error, isLoading, refetch } = useQuery('advice', fetchAdvice, {
refetchOnWindowFocus: false,
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>An error occurred</div>;
return (
<div>
<h1>{advice}</h1>
<button onClick={() => refetch()}>Get New Advice</button>
</div>
);
}
export default AdviceGenerator;
With useQuery
, we delegate the loading and error handling to React Query, significantly simplifying our code.
Installation
Getting started with useQuery
in a Next.js project is straightforward. First, you need to install the React Query library:
npm install @tanstack/react-query
or
yarn add @tanstack/react-query
Basic Usage
Let's look at a simple example where we fetch data from an API and display it in a Next.js component.
Step 1: Setting Up the Query Client
First, you'll need to set up the React Query client in your _app.js
or _app.tsx
file.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const MyApp = ({ Component, pageProps }) => (
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
</QueryClientProvider>
);
export default MyApp;
Step 2: Using useQuery
in a Component
Now, let's create a component that uses useQuery
to fetch data.
import { useQuery, useQueryClient } from '@tanstack/react-query';
const fetchAdvice = async () => {
const response = await fetch('https://api.adviceslip.com/advice');
const data = await response.json();
return data.slip.advice;
};
const AdviceGenerator = () => {
const queryClient = useQueryClient();
const { data: advice, error, isLoading, refetch } = useQuery('advice', fetchAdvice, {
refetchOnWindowFocus: false,
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>An error occurred</div>;
return (
<div>
<h1>{advice}</h1>
<button onClick={() => refetch()}>Get New Advice</button>
</div>
);
}
export default AdviceGenerator;
Smart Caching
One of the standout features of useQuery
is its smart caching mechanism. When you fetch data with useQuery
, it automatically caches the results. This means that if you request the same data again, useQuery
can serve it from the cache instead of making a new network request. This not only improves performance but also provides a smoother user experience. The cache is intelligently invalidated and updated based on your configuration, ensuring that your app always has fresh and accurate data.
Advanced Usage
React Query offers a lot of flexibility and advanced features to handle more complex use cases.
Fetching Advice by ID with Dependent Queries
Query keys can be dynamic, allowing you to fetch data based on different parameters. Additionally, you can use the enabled
option to create dependent queries that only run when certain conditions are met.
const fetchAdviceById = async (id) => {
const response = await fetch(`https://api.adviceslip.com/advice/${id}`);
const data = await response.json();
return data.slip.advice;
};
const AdviceGeneratorById = ({ adviceId }) => {
const { data: advice, error, isLoading, refetch } = useQuery(
['advice', adviceId],
() => fetchAdviceById(adviceId),
{
enabled: !!adviceId, // The query will only run if adviceId is truthy
}
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>An error occurred</div>;
return (
<div>
<h1>{advice}</h1>
<button onClick={() => refetch()}>Get New Advice</button>
</div>
);
}
export default AdviceGeneratorById;
Conclusion
As you can see, useQuery
from React Query provides a powerful and flexible solution for managing server state in your Next.js applications. By leveraging its capabilities, you can simplify your data fetching logic, benefit from smart caching, and handle more complex use cases with ease. Whether you're building a simple advice generator or a more complex app, useQuery
can help you streamline your development process and enhance your app's performance. Give it a try in your next project and experience the difference!
Additional Resources
Subscribe to my newsletter
Read articles from Yujan Prajapati directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by