Skip to content

Instantly share code, notes, and snippets.

@Gaurav8757
Last active January 2, 2026 07:05
Show Gist options
  • Select an option

  • Save Gaurav8757/bdb1d59d9311baeea97e13524f55d994 to your computer and use it in GitHub Desktop.

Select an option

Save Gaurav8757/bdb1d59d9311baeea97e13524f55d994 to your computer and use it in GitHub Desktop.
useMutation from '@tanstack/react-query';
// apis/APIs.js
class ApiServices {
async updateProfile(data) {
try {
const res = await api.put("/user/update-profile", data);
return res?.data;
} catch (error) {
throw error.response?.data || error;
} finally {
console.log("updateProfile: FINALLY executed");
}
}
async logoutUser() {
try {
const res = await api.post("/user/logout");
return res?.data;
} catch (err) {
throw err.response?.data || err;
} finally {
console.log("logoutUser: FINALLY executed");
}
}
}
export default new ApiServices();
// Reusable useMutation Hook Pattern (Global Handling)
// Way-1 (Success, Error, Finally all inside hook)
// hooks/useUpdateProfile.js
import { useMutation } from "@tanstack/react-query";
import ApiServices from "../../apis/APIs.js";
import { toast } from "react-hot-toast";
export const useUpdateProfile = () => {
return useMutation({
mutationFn: async (payload) => {
const res = await ApiServices.updateProfile(payload);
if (!res?.success) {
throw new Error(res?.message || "Update failed");
}
return res;
},
// ⭐ SUCCESS
onSuccess: (data) => {
console.log("Profile Updated Successfully");
toast.success(data?.message || "Updated!");
},
// ❌ ERROR
onError: (error) => {
console.error("Update Profile Error →", error?.message);
toast.error(error?.message || "Something went wrong");
},
// 🔥 FINALLY (always executed)
onSettled: () => {
console.log("Update Profile: FINALLY executed");
},
});
};
// Usage in Component
import { useUpdateProfile } from "../hooks/useUpdateProfile";
export default function ProfilePage() {
const { mutate, isPending, isSuccess, isError } = useUpdateProfile();
const handleUpdate = () => {
mutate({
username: "Gaurav Kumar",
age: 23,
});
};
return (
<div className="p-4">
<button
onClick={handleUpdate}
disabled={isPending}
className="bg-blue-600 text-white rounded px-4 py-2"
>
{isPending ? "Saving..." : "Save Profile"}
</button>
{isSuccess && <p className="text-green-600 mt-2">Profile Updated</p>}
{isError && <p className="text-red-600 mt-2">Failed to update</p>}
</div>
);
}
// Way 2: Simple Component-Handled Mutation
// hooks/useLogoutUser.js
import { useMutation } from "@tanstack/react-query";
import ApiServices from "../../apis/APIs.js";
export const useLogoutUser = () => {
return useMutation({
mutationFn: ApiServices.logoutUser,
retry: 1,
});
};
// Component
import { useLogoutUser } from "../hooks/useLogoutUser";
import { toast } from "react-hot-toast";
export default function LogoutButton() {
const { mutate, isPending } = useLogoutUser();
const handleLogout = () => {
mutate(null, {
onSuccess: (data) => {
toast.success(data?.message || "Logged out");
},
onError: (err) => {
toast.error(err?.message || "Logout failed");
},
});
};
return (
<button
onClick={handleLogout}
disabled={isPending}
className="bg-red-500 text-white px-4 py-2 rounded"
>
{isPending ? "Logging out..." : "Logout"}
</button>
);
}
// Mutation + Cache Invalidation (Important for Real Projects)
import { useMutation, useQueryClient } from "@tanstack/react-query";
export const useUpdateProfile = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ApiServices.updateProfile,
onSuccess: () => {
queryClient.invalidateQueries(["getLoginedUserInfo"]);
},
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment