Building CRUD Operations with TanStack Query

TanStack Query makes building CRUD (Create, Read, Update, Delete) operations seamless by providing tools for efficient data fetching, mutation handling, and cache management. This tutorial walks you through implementing CRUD operations in a React application using TanStack Query.


Prerequisites

Basic knowledge of React.

A REST API endpoint for demonstration (e.g., https://jsonplaceholder.typicode.com).

Install TanStack Query:

npm install @tanstack/react-query

npm install @tanstack/react-query-devtools


Step 1: Setting Up the Query Client

Before building CRUD operations, set up the QueryClient to manage queries and mutations.


App.js

import React from 'react';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

import { Posts } from './Posts';


const queryClient = new QueryClient();


function App() {

  return (

    <QueryClientProvider client={queryClient}>

      <h1>TanStack Query CRUD Example</h1>

      <Posts />

      <ReactQueryDevtools initialIsOpen={false} />

    </QueryClientProvider>

  );

}


export default App;

Step 2: Fetching Data (READ Operation)

Use the useQuery hook to fetch and cache data.


Posts.js

import React from 'react';

import { useQuery } from '@tanstack/react-query';


const fetchPosts = async () => {

  const response = await fetch('https://jsonplaceholder.typicode.com/posts');

  if (!response.ok) throw new Error('Failed to fetch posts');

  return response.json();

};


export function Posts() {

  const { data, isLoading, isError, error } = useQuery(['posts'], fetchPosts);


  if (isLoading) return <p>Loading posts...</p>;

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


  return (

    <ul>

      {data.map((post) => (

        <li key={post.id}>{post.title}</li>

      ))}

    </ul>

  );

}


Step 3: Creating Data (CREATE Operation)

Use the useMutation hook to handle POST requests and update the cache.


CreatePost.js

import React, { useState } from 'react';

import { useMutation, useQueryClient } from '@tanstack/react-query';


const createPost = async (newPost) => {

  const response = await fetch('https://jsonplaceholder.typicode.com/posts', {

    method: 'POST',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify(newPost),

  });

  if (!response.ok) throw new Error('Failed to create post');

  return response.json();

};


export function CreatePost() {

  const [title, setTitle] = useState('');

  const queryClient = useQueryClient();


  const mutation = useMutation(createPost, {

    onSuccess: () => {

      queryClient.invalidateQueries(['posts']); // Refetch posts

    },

  });


  const handleSubmit = (e) => {

    e.preventDefault();

    mutation.mutate({ title });

    setTitle('');

  };


  return (

    <form onSubmit={handleSubmit}>

      <input

        type="text"

        value={title}

        onChange={(e) => setTitle(e.target.value)}

        placeholder="Enter post title"

        required

      />

      <button type="submit">Create Post</button>

    </form>

  );

}


Step 4: Updating Data (UPDATE Operation)

Handle updates using useMutation and patch the data on the server.


UpdatePost.js

import React, { useState } from 'react';

import { useMutation, useQueryClient } from '@tanstack/react-query';


const updatePost = async ({ id, title }) => {

  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {

    method: 'PATCH',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify({ title }),

  });

  if (!response.ok) throw new Error('Failed to update post');

  return response.json();

};


export function UpdatePost({ id, currentTitle }) {

  const [title, setTitle] = useState(currentTitle);

  const queryClient = useQueryClient();


  const mutation = useMutation(updatePost, {

    onSuccess: () => {

      queryClient.invalidateQueries(['posts']); // Refetch posts

    },

  });


  const handleSubmit = (e) => {

    e.preventDefault();

    mutation.mutate({ id, title });

  };


  return (

    <form onSubmit={handleSubmit}>

      <input

        type="text"

        value={title}

        onChange={(e) => setTitle(e.target.value)}

        required

      />

      <button type="submit">Update Post</button>

    </form>

  );

}


Step 5: Deleting Data (DELETE Operation)

Use useMutation for DELETE requests.


DeletePost.js

import React from 'react';

import { useMutation, useQueryClient } from '@tanstack/react-query';


const deletePost = async (id) => {

  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {

    method: 'DELETE',

  });

  if (!response.ok) throw new Error('Failed to delete post');

  return id;

};


export function DeletePost({ id }) {

  const queryClient = useQueryClient();


  const mutation = useMutation(deletePost, {

    onSuccess: () => {

      queryClient.invalidateQueries(['posts']); // Refetch posts

    },

  });


  return <button onClick={() => mutation.mutate(id)}>Delete Post</button>;

}


Step 6: Combining CRUD Operations

Integrate all components into a single view.


App.js

import React from 'react';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import { Posts } from './Posts';

import { CreatePost } from './CreatePost';


const queryClient = new QueryClient();


function App() {

  return (

    <QueryClientProvider client={queryClient}>

      <h1>CRUD with TanStack Query</h1>

      <CreatePost />

      <Posts />

    </QueryClientProvider>

  );

}


export default App;

Best Practices

  • Invalidate Queries: Always invalidate queries to refresh cache after mutations.
  • Error Handling: Use onError in mutations to gracefully handle errors.
  • Optimistic Updates: Consider implementing optimistic updates for faster UI feedback.


In this tutorial, you’ve learned how to:

  • Fetch and display data using useQuery.
  • Create, update, and delete data using useMutation.
  • Manage cache efficiently with query invalidation.

TanStack Query simplifies building robust CRUD operations with minimal effort.  Hope this is helpful, and I apologize if there are any inaccuracies in the information provided.

Comments

Popular posts from this blog

Integrating PHP with Message Queues RabbitMQ Kafka

FastAPI and UVLoop: The Perfect Pair for Asynchronous API Development

Konfigurasi dan Instalasi PostgreSQL Secara Lengkap di Windows Linux dan MacOS