Simplifying Data Fetching in React with Axios and React Query in Next.js

Khalif AL Mahmud - Oct 22 - - Dev Community

React Query is a powerful library that simplifies data fetching, caching, and state management in React applications. When combined with Next.js, a popular server-side rendering framework for React, it becomes even more effective in handling CRUD operations. In this blog, we’ll explore how to use React Query with Next.js to perform Create, Read, Update, and Delete (CRUD) operations using Axios for data handling.

Assuming you have a new or existing Next.js project, install the required packages:

npm install axios react-query
Enter fullscreen mode Exit fullscreen mode

Step 1: Creating the API Functions:

Create separate functions to handle CRUD operations using Axios. These functions will interact with your API server. For simplicity, we’ll create a fictional example of managing “todos.”

// utils/api.js
import axios from "axios";
const apiUrl = "https://api.example.com/todos";
export const fetchTodos = () => axios.get(apiUrl);
export const createTodo = (todo) => axios.post(apiUrl, todo);
export const updateTodo = (id, todo) => axios.put(`${apiUrl}/${id}`, todo);
export const deleteTodo = (id) => axios.delete(`${apiUrl}/${id}`);
Enter fullscreen mode Exit fullscreen mode

Step 2: Setting up React Query:

In your Next.js application, create a react-query client and wrap your application with the QueryClientProvider.

// pages/_app.js
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();

function MyApp({ Component, pageProps }) {
 return (
  <QueryClientProvider client={queryClient}>
   <Component {...pageProps} />
  </QueryClientProvider>
 );
}
export default MyApp;
Enter fullscreen mode Exit fullscreen mode

Step 3: Fetching Todos using React Query:

In your component, use the useQuery hook provided by React Query to fetch and cache the todos.

// pages/index.js
import { useQuery } from "react-query";
import { fetchTodos } from "../utils/api";

function TodoList() {
 const { data: todos, isLoading, error } = useQuery("todos", fetchTodos);

 if (isLoading) return <div>Loading...</div>;

 if (error) return <div>Error: {error.message}</div>;

 return (
  <div>
   {todos.map((todo) => (
    <div key={todo.id}>{todo.title}</div>
   ))}
  </div>
 );
}

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

Step 4: Creating a New Todo:

Let’s add a form to create a new todo using the useMutation hook from React Query.

// pages/index.js
import { useQuery, useMutation } from "react-query";
import { fetchTodos, createTodo } from "../utils/api";

function TodoList() {
 // ... Same code as before ...

 const mutation = useMutation(createTodo, {
  onSuccess: () => {
   queryClient.invalidateQueries("todos");
  },
 });

 const handleAddTodo = (event) => {
  event.preventDefault();
  const formData = new FormData(event.target);
  const title = formData.get("title");
  mutation.mutate({ title });
 };

 return (
  <div>
   {todos.map((todo) => (
    <div key={todo.id}>{todo.title}</div>
   ))}

   <form onSubmit={handleAddTodo}>
    <input type="text" name="title" placeholder="Enter todo title" />
    <button type="submit">Add Todo</button>
   </form>
  </div>
 );
}

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

Step 5: Updating and Deleting Todos:

We’ll follow a similar approach for updating and deleting todos.

// pages/index.js
import { useQuery, useMutation } from "react-query";
import { fetchTodos, createTodo, updateTodo, deleteTodo } from "../utils/api";

function TodoList() {
 // ... Same code as before ...

 const updateMutation = useMutation(updateTodo, {
  onSuccess: () => {
   queryClient.invalidateQueries("todos");
  },
 });

 const deleteMutation = useMutation(deleteTodo, {
  onSuccess: () => {
   queryClient.invalidateQueries("todos");
  },
 });

 const handleUpdateTodo = (id, newTitle) => {
  updateMutation.mutate({ id, title: newTitle });
 };

 const handleDeleteTodo = (id) => {
  deleteMutation.mutate(id);
 };

 return (
  <div>
   {todos.map((todo) => (
    <div key={todo.id}>
     <input
      type="text"
      value={todo.title}
      onChange={(e) => handleUpdateTodo(todo.id, e.target.value)}
     />
     <button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
    </div>
   ))}

   <form onSubmit={handleAddTodo}>
    <input type="text" name="title" placeholder="Enter todo title" />
    <button type="submit">Add Todo</button>
   </form>
  </div>
 );
}

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

By integrating React Query with Next.js and Axios, we’ve successfully implemented CRUD operations for managing todos in our application. React Query’s powerful caching and data synchronization features make it an excellent choice for handling complex data scenarios. As you continue to build your application, remember to follow similar patterns for other data entities and actions as needed.

Happy coding!

. . . . . . .