0

I'm creating a next js 14 project with react hook form/zod + react query and also using next js api route handlers as my backend plus I'm using next auth to Google auth but I think that my current issue is not about next auth

So I have a RSC component called CreatePetPage:

import FormAuthCreatePet from "@/components/FormAuthCreatePet";


export default async function CreatePetPage() {

 

  return (
    <main className="flex w-full h-full">

    <div className="h-screen w-full">
   
      <div className="w-full h-20 flex items-center  px-4 
  border-b border-b-slate-300">
        <h3 className="text-brand-secondary text-2xl">New Pet</h3>
         
      </div>
      <div className="w-full h-[calc(100%-5rem)] flex items-center justify-center">
          <FormAuthCreatePet/>
      </div>
    </div>
  </main>
  )
}

and inside FormAuthCreatePet component that is an client component i have:

"use client"

import { ImSpinner9 } from "react-icons/im";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import {  useMutation, useQueryClient } from "@tanstack/react-query";
import { addPet } from "@/utils/actions/AddPet";

export async function addPet(dataForm:CreatePetSchema){

    await fetch("http://localhost:3000/api/pets/create",{
      method:"POST",
     headers:{
        "Content-Type":"application/json"
     },
     body: JSON.stringify(dataForm)
    })
  
  
  }


const createPetSchema = z.object({
  name: z.string(),
  age: z.coerce.number()
});

type CreatePetSchema = z.infer<typeof createPetSchema>;

export default function FormAuthCreatePet() {

  const {handleSubmit,register,formState:{isSubmitting}} = useForm<CreatePetSchema>({
    resolver: zodResolver(createPetSchema)
  })
 
  const queryClient = useQueryClient()
  const {data:session} = useSession() 
  const router = useRouter()
  

  const {mutateAsync:createPet} = useMutation({
    mutationFn: addPet,
    onSuccess: () =>{
      queryClient.invalidateQueries({queryKey:['pets']})
    }

  })

    async function OnSubmit(data:CreatePetSchema){
    const dataForm =  {...data,userEmail:session?.user?.email}

    
      try {
        await createPet(dataForm)
        router.push("/dashboard")
      } catch (error) {
        console.log(error);
        
      }

     
    }
    
  return (
    <div className='h-[90%] w-[90%] '>

        <form action="" className='flex flex-col justify-center items-center h-full gap-6'
        onSubmit={handleSubmit(OnSubmit)}>

            <label htmlFor="name">Pet Name</label>
            <input className='py-1 bg-slate-200'
             id='name'
            {...register("name",{required:true})} 
            />

            <label htmlFor="age">Age</label>
            <input className='py-1 bg-slate-200' 
             id='age'
             {...register("age",{required:true})} 
             />

            <button type='submit' 
            disabled={isSubmitting}
            className='text-brand-secondary font-semibold px-3 py-1 bg-blue-100 opacity-80
            disabled:bg-slate-300 disabled:px-4 disabled:py-2'> {isSubmitting ?<ImSpinner9/> : "Done"}
            </button>

        </form>
    </div>
  )
}

So, in this component above in my mind, it should invalidate queryKey "pets", right? But in my project where I fetch my pets, it is not refetching my data that it is supposed to do because my query is invalid, right?

So here is where I fetch my "pets" inside PetCard(client component) which is a component in PetsPage rsc

PetsPage:

import PetCard from "@/components/petCard";
import { getAllPets } from "@/utils/actions/GetAllPets";
import { dehydrate,HydrationBoundary,QueryClient } from "@tanstack/react-query";

export async function getAllPets (){
    const session = await auth()
    const resp = await fetch("http://localhost:3000/api/pets",{
      headers:{
           'session': JSON.stringify(session)
      }
     })
    const data = await resp.json()
  
    return data
  }


export default async function PetsPage() {

    const queryClient = new QueryClient()
    await queryClient.prefetchQuery({
      queryKey:['pets'],
      queryFn: getAllPets
    })
   
    
  return (
    <main className="h-screen w-full flex justify-center items-center ">
      <HydrationBoundary state={dehydrate(queryClient)}>
        <PetCard/>
      </HydrationBoundary>
    </main>
    );
}

PetCard component:

"use client"

import { Pet } from "@/app/(auth)/dashboard/page";
import { getAllPets } from "@/utils/actions/GetAllPets";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";


async function deletePet(petId:string){
  await fetch(`http://localhost:3000/api/pets/${petId}`,{
    method:"DELETE"
  })
}


export default function PetCard() {

 
  const queryClient = useQueryClient()

  const { data } = useQuery({
    queryKey: ['pets'],
    queryFn: getAllPets
  })

  const {mutate:removePetById} = useMutation({
    mutationFn: deletePet,
    onSuccess: () => {
      queryClient.invalidateQueries({queryKey:['pets']})
      console.log("it runs!");
      
    }

  })


    async function handleRemovePet(petId:string){

       try {
         removePetById(petId)
       } catch (error) {
        console.log(error);
        
       }
       }

  return (
    <div className="h-[70%] w-[70%] flex gap-10 items-center justify-center ">
        {
        data.map((pet:Pet) =>(
          <div className="flex-1 flex-wrap relative p-4 bg-brand-third text-white" key={pet.id}>
            <button className="absolute top-0 right-0 hover:bg-slate-200 p-2 hover:text-red-500"
            onClick={() =>  handleRemovePet(pet.id)}>X</button>
              <p>Pet Name: {pet.name}</p>
              <p>Pet age: {pet.age}</p>
          </div>
        ))
         }
      </div>
  )
}

So, as I said, when I click and trigger handleRemovePet inside my database using my API route handler from next js the pet is being removed but it's not reflecting in my UI, so it is not invalidating my query and refreshing the data. Please help me, as I said in my mind this should been working just fine!

I tried to change the code many times but as I said in my mind, it should work just fine.

2
  • Try queryClient.invalidateQueries('pets'). Also, check whether console.log('it runs') is printing or not. Commented Mar 7, 2024 at 10:08
  • Hi @ManuBenjamin thanks for the answer. I tried the console.log("onSucces working") inside onSucces() and it is working fine because it is printing ''onSucces working'' in my browser console after my mutation runs and I also tried do put queryClient.invalidateQueries('pets') instead queryClient.invalidateQueries({queryKey:['pets']}) . But is still not working i got the same issue : My UI it's not getting refreshed by invalidating the querie and refreshing my data doing another fetch. Commented Mar 7, 2024 at 16:19

1 Answer 1

0

How i fixed it ?

So guys as i said in my post : the queryClient.invalidateQueries to invalidate queries isn't working in my project . So to keep doing my project i had to : use the query queryClient.getQueryData(["pets"]) to get my cached query "pets" and use queryClient.setQueryData() by passing in the first argument my queryKey: ["pets"] and as second argument a function (I knew that by reading the tanstack query docs).

My code alternative was this one for PetCard Component:

onSuccess (_,variables) {
     const petId = variables
     const cached = queryClient.getQueryData(["pets"])

     
      queryClient.setQueryData(["pets"], data =>{
       const filteredPets = cached.filter((pet) =>{
            return pet.id !== petId
       })
      return filteredPets
    })
  
         
    }

And to my another FormAuthCreatePet component inside my another page :

onSuccess (data,variables,context) {
      const cached = queryClient.getQueryData(["pets"])

      queryClient.setQueryData(["pets"], data =>{
        return [
          ...data,{
            age: variables.age,
            name: variables.name,
            userEmail: variables.userEmail
          }

        ]
      })
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.