Last active
March 7, 2025 14:15
-
-
Save subrotoice/d99078e87148587667f5d055b18f6e9f to your computer and use it in GitHub Desktop.
Nextjs -> ReactComponet -> ReactQuery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Nextjs page.tsx | |
const getPosts = async () => { | |
const res = await fetch("https://jsonplaceholder.typicode.com/posts"); | |
return res.json(); | |
}; | |
export default async function PostsPage() { | |
const posts = await getPosts(); // Fetch posts on the server | |
return <PostsList initialPosts={posts} />; | |
} | |
// PostsList.tsx | |
"use client"; | |
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; | |
import { useState } from "react"; | |
import APIClient from "./_services/api-client"; | |
type Post = { | |
id: number; | |
title: string; | |
body: string; | |
}; | |
export default function PostsList({ initialPosts }: { initialPosts: Post[] }) { | |
const queryClient = useQueryClient(); | |
const apiClient = new APIClient<Post>("/posts"); | |
const { data } = useQuery({ | |
queryKey: ["posts"], | |
queryFn: apiClient.getAll, | |
staleTime: 10 * 1000, | |
refetchOnWindowFocus: false, | |
refetchOnReconnect: false, | |
refetchOnMount: false, | |
initialData: initialPosts, | |
retry: 2, | |
}); | |
const createMutation = useMutation({ | |
mutationFn: apiClient.post, | |
onSuccess: (savedPost, newPost) => { | |
console.log(savedPost); | |
queryClient.setQueryData<Post[]>(["posts"], (posts) => [ | |
savedPost, | |
...(posts || []), | |
]); | |
}, | |
}); | |
// UPDATE Post | |
const updateMutation = useMutation({ | |
mutationFn: ({ | |
id, | |
updatedPost, | |
}: { | |
id: number; | |
updatedPost: Omit<Post, "id">; | |
}) => apiClient.put(id, updatedPost), | |
onSuccess: (savedData, { id }) => { | |
console.log(id); // Logs the updated post ID | |
console.log(savedData); // Logs the updated post data | |
queryClient.setQueryData(["posts"], (oldData: Post[] | undefined) => | |
oldData | |
? oldData.map((post) => | |
post.id === id ? { ...post, ...savedData } : post | |
) | |
: [] | |
); | |
}, | |
}); | |
// DELETE Post | |
const deleteMutation = useMutation({ | |
mutationFn: apiClient.delete, | |
onSuccess: (savedData, id) => { | |
console.log(id); // This will log the deleted post ID | |
console.log(savedData); // This will log the deleted post ID | |
queryClient.setQueryData(["posts"], (oldData: Post[] | undefined) => | |
oldData ? oldData.filter((post) => post.id !== id) : [] | |
); | |
}, | |
}); | |
const [newPost, setNewPost] = useState({ title: "", body: "" }); | |
return ( | |
<div className="flex flex-col"> | |
<h1>PostsList.tsx</h1> | |
<input | |
type="text" | |
className="border" | |
placeholder="Title" | |
value={newPost.title} | |
onChange={(e) => setNewPost({ ...newPost, title: e.target.value })} | |
/> | |
<textarea | |
placeholder="Body" | |
className="border" | |
value={newPost.body} | |
onChange={(e) => setNewPost({ ...newPost, body: e.target.value })} | |
/> | |
<button onClick={() => createMutation.mutate(newPost)}>Add Post</button> | |
<ul> | |
{data?.map((post) => ( | |
<li className="border bottom-1" key={post.id}> | |
<h3> | |
{post.id}.{post.title} | |
</h3> | |
<p>{post.body}</p> | |
<button | |
className="border m-1 p-1" | |
onClick={() => | |
updateMutation.mutate({ | |
id: post.id, | |
updatedPost: { ...newPost, title: post.title + "!" }, | |
}) | |
} | |
> | |
Update {post.id} | |
</button> | |
<button onClick={() => deleteMutation.mutate(post.id)}> | |
Delete | |
</button> | |
</li> | |
))} | |
</ul> | |
</div> | |
); | |
} | |
// api-client.ts | |
import axios, { AxiosRequestConfig } from "axios"; | |
export interface FetchResponse<T> { | |
count: number; | |
next: string | null; | |
results: T[]; | |
} | |
const axiosInstance = axios.create({ | |
baseURL: "https://jsonplaceholder.typicode.com", | |
}); | |
class APIClient<T> { | |
endPoint: string; | |
constructor(endPoint: string) { | |
this.endPoint = endPoint; | |
} | |
getAll = (config?: AxiosRequestConfig) => { | |
return axiosInstance | |
.get<FetchResponse<T>>(this.endPoint, config) | |
.then((res) => res.data.results); | |
}; | |
get = (id: number | string, config?: AxiosRequestConfig) => { | |
return axiosInstance | |
.get<T>(`${this.endPoint}/${id}`, config) | |
.then((res) => res.data); | |
}; | |
post = (data: Partial<T>, config?: AxiosRequestConfig) => { | |
return axiosInstance | |
.post<T>(this.endPoint, data, config) | |
.then((res) => res.data); | |
}; | |
put = ( | |
id: number | string, | |
data: Partial<T>, | |
config?: AxiosRequestConfig | |
) => { | |
return axiosInstance | |
.put<T>(`${this.endPoint}/${id}`, data, config) | |
.then((res) => res.data); | |
}; | |
delete = (id: number | string, config?: AxiosRequestConfig) => { | |
return axiosInstance | |
.delete(`${this.endPoint}/${id}`, config) | |
.then((res) => res.data); | |
}; | |
} | |
export default APIClient; | |
Comments are disabled for this gist.