When the first mount happens, everything works fine, but when I refresh the page (and only when I refresh the page) I get this error.
VM7552 page.tsx:40 Error fetching data:
{code: ‘PGRST301’, details: null, hint: null, message: ‘JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 1)’}
code
:
“PGRST301”
details
:
null
hint
:
null
message
:
“JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 1)”
If I don’t use useEffect, and just create a button that fetches on click, everything works fine, and when added a dependency (it didn’t matter what dependency I added) they all had the same problem, which was making the useEffect loop infinitely
/profile/[id]
export default function Profile() {
const { getEntries, deleteEntry } = useEntries();
const [entries, setEntries] = useState<Entry[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
async function fetchEntries() {
setLoading(true);
try {
const fetchedEntries = await getEntries();
setEntries(fetchedEntries);
console.log(entries);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
}
fetchEntries();
}, []);
// rest of the code
/api/entries.ts
import { useClerkSupabaseClient } from "@/services/supabase";
import { AddEntryProps } from "@/types";
import { useAuth } from "@clerk/nextjs";
export function useEntries() {
const { userId } = useAuth();
const supabase = useClerkSupabaseClient();
if (!supabase) {
throw new Error("Supabase client is not initialized");
}
async function addEntry({ prompt, entry }: AddEntryProps) {
if (!userId) {
throw new Error("User ID is missing, cannot add entry");
}
const { data, error } = await supabase
.from("Entries")
.insert([{ prompt, entry, user_id: userId }])
.select();
if (error) {
console.error("Error inserting Entry:", error.message || error);
throw error;
}
return data;
}
async function getEntries() {
if (!userId) {
throw new Error("User ID is missing, cannot fetch entries");
}
const { data, error } = await supabase
.from("Entries")
.select("*")
.eq("user_id", userId);
if (error) {
console.error("Error getting Entry:", error.message || error);
throw error;
}
return data;
}
// rest of the code
/services/supabase.ts
import { useSession } from "@clerk/nextjs";
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { useMemo } from "react";
//? Supabase client instance
let supabase: SupabaseClient | null = null;
export function useClerkSupabaseClient() {
const { session } = useSession();
return useMemo(() => {
if (!supabase) {
//? Create the Supabase client instance if it doesn't exist
supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_KEY!,
{
global: {
fetch: async (url, options = {}) => {
//? Get Clerk token
const clerkToken = await session?.getToken({
template: "supabase",
});
const headers = new Headers(options?.headers);
headers.set("Authorization", `Bearer ${clerkToken}`);
return fetch(url, {
...options,
headers,
});
},
},
}
);
}
//? Return the singleton Supabase client
return supabase;
}, [session]);
}