Skip to content

Instantly share code, notes, and snippets.

@subrotoice
Last active March 7, 2025 14:15
Show Gist options
  • Save subrotoice/d99078e87148587667f5d055b18f6e9f to your computer and use it in GitHub Desktop.
Save subrotoice/d99078e87148587667f5d055b18f6e9f to your computer and use it in GitHub Desktop.
Nextjs -> ReactComponet -> ReactQuery
// 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.