How can I fetch data in my component

Here is the link to stackoverflow.com displaying how I implemented it https://stackoverflow.com/q/76112994/19684000
Stack Overflow
Rendering fetched data from supabase in Nextjs13 App Directory
I successfully fetched data from supabase but I am unable to render them in my component , I tried implemented a component to hold the fetched data but i was unable to as it arose to other errors t...
79 Replies
froxx
froxx14mo ago
Im not familiar with supabase, but the general way of calling your endpoint, wait for a response, and set the result to a state variable in your component looks right. You should probably add am empty dependency array to your useEffect though. Apart from that a bit more information on what's going wrong in your example would help solving the cause. Also you're not rendering the "profiles" state in your component yet
Revaycolizer
Revaycolizer14mo ago
I didn't include rendering because no matter how I tried to render I got errors
Pitus
Pitus14mo ago
Hey, are you using t3 stack? if so it's better to make it with prisma seems like what you're trying to do is to fetch users data. I suggest you to use following provider and use User hook:
import React, { createContext, useContext, useEffect, useState } from "react";
import type { Session, User } from "@supabase/supabase-js";
import { supabase } from "~/utils/supabase-client";

export const AuthContext = createContext<{
user: User | null;
session: Session | null;
isLoading: boolean;
}>({
user: null,
session: null,
isLoading: true,
});

export const AuthContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [userSession, setUserSession] = useState<Session | null>(null);
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
void supabase.auth.getSession().then(({ data: { session } }) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
});

const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
}
);

return () => {
authListener.subscription.unsubscribe();
};
}, []);

const value = {
session: userSession,
user,
isLoading,
};

return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export const useUser = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useUser must be used within a AuthContextProvider.");
}
return context;
};
import React, { createContext, useContext, useEffect, useState } from "react";
import type { Session, User } from "@supabase/supabase-js";
import { supabase } from "~/utils/supabase-client";

export const AuthContext = createContext<{
user: User | null;
session: Session | null;
isLoading: boolean;
}>({
user: null,
session: null,
isLoading: true,
});

export const AuthContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [userSession, setUserSession] = useState<Session | null>(null);
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
void supabase.auth.getSession().then(({ data: { session } }) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
});

const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
}
);

return () => {
authListener.subscription.unsubscribe();
};
}, []);

const value = {
session: userSession,
user,
isLoading,
};

return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export const useUser = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useUser must be used within a AuthContextProvider.");
}
return context;
};
then you can just use it as
consr {user} = useUser()
consr {user} = useUser()
but that's from supabse auth.user if you want to fetch data of users profile you would have to set up supabse user management (check our sql editor and default templates) and then fetch from public.profile (or profiles I don't remember)
Pitus
Pitus14mo ago
check out how I'm using it, here's an t3 + supabse app I built like a week ago: https://github.com/F-PTS/FriendlyMacros maybe it would help you
GitHub
GitHub - F-PTS/FriendlyMacros
Contribute to F-PTS/FriendlyMacros development by creating an account on GitHub.
Pitus
Pitus14mo ago
there's a bit of antipatterns in code you've put on stack overflow (e.g. useEffect without dependency array, using any types, etc.) I think FriendlyMacros repo would help you understand what good practices in react, next, prisma, trpc and supabase are
Revaycolizer
Revaycolizer14mo ago
i am using supabase with nextjs without prisma thanks bruh but this one i used nextjs 13.3.1 App Directory and Supabase i included codes where i am performing rendering i successfully fetch them but I am unable to render them
Pitus
Pitus14mo ago
yeah same, i just used trpc and prisma as well but shouldnt be any trouble since its just a context provider how come?
Revaycolizer
Revaycolizer14mo ago
as i console log the data of a specific user i saw them but rendering it throws an error i added Profile.tsx component in stackocerflow you used new App Directory?
Pitus
Pitus14mo ago
yes what was the error?
Revaycolizer
Revaycolizer14mo ago
let me screenshot it now
Pitus
Pitus14mo ago
also, why are you using React.FC<ProfileProps> ? the default way of making functional component would be just fine I think
Revaycolizer
Revaycolizer14mo ago
i shifted from prisma as i was only able to migrate model into the database but i was unable to perform user registration that's why i decided to shift to pure supabase as i always do when i am using vue 3 which one
Pitus
Pitus14mo ago
Profile.tsx
import React from 'react'
interface ProfileProps{
name?:string;
email?:string;
phone?: string;
}

const profile: ProfileProps={}

const Profile:React.FC<ProfileProps> = () => {
return (
<div className='justify-center items-center flex flex-col bg-green-100'>
<p>Name:{profile.name}</p>
<p>Email:{profile.email}</p>
<p>Phone:{profile.phone}</p>
</div>
)
}

export default Profile
import React from 'react'
interface ProfileProps{
name?:string;
email?:string;
phone?: string;
}

const profile: ProfileProps={}

const Profile:React.FC<ProfileProps> = () => {
return (
<div className='justify-center items-center flex flex-col bg-green-100'>
<p>Name:{profile.name}</p>
<p>Email:{profile.email}</p>
<p>Phone:{profile.phone}</p>
</div>
)
}

export default Profile
What would the point of React.FC and not
const Profile = ({profile}: {profile: ProfileProps}) => {
return (
<div className='justify-center items-center flex flex-col bg-green-100'>
<p>Name:{profile.name}</p>
<p>Email:{profile.email}</p>
<p>Phone:{profile.phone}</p>
</div>
)
}
const Profile = ({profile}: {profile: ProfileProps}) => {
return (
<div className='justify-center items-center flex flex-col bg-green-100'>
<p>Name:{profile.name}</p>
<p>Email:{profile.email}</p>
<p>Phone:{profile.phone}</p>
</div>
)
}
Revaycolizer
Revaycolizer14mo ago
this is the error i am facing
Pitus
Pitus14mo ago
yeah great but let me see the error message hover over it oh yeah i think I know what are doing
Revaycolizer
Revaycolizer14mo ago
this one throws some error
Pitus
Pitus14mo ago
you specified in Profile.tsx that profile has to be type of ProfileProps. Meanwhile you are passing any into it let me see an error message
Revaycolizer
Revaycolizer14mo ago
this one
Revaycolizer
Revaycolizer14mo ago
should i pass a string?
Pitus
Pitus14mo ago
well no wonder it cannot find ProfileProps since you commented it out. Remove comments from the interface and delete 8th line
Revaycolizer
Revaycolizer14mo ago
done then should i try to see if the data can be displayed?
Pitus
Pitus14mo ago
do you have a way of getting a type of your profile in your page.tsx?
Revaycolizer
Revaycolizer14mo ago
thanks bruh they are retrieved successfully
Pitus
Pitus14mo ago
because if you do, you should change :any type to the type of your response but do not import the type from @prisma/client. You shouldn't mix backend and front end types (not a good practice)
Revaycolizer
Revaycolizer14mo ago
i was able bruh thanks to you now i will be thinking only about implementing middleware i am using pure nextjs and supabase bruh
Pitus
Pitus14mo ago
yeah sure, also keep in mind that you should almost never (unless in app directory) use export default. Use export instead oh right i brain farted lol supabase could generate your types tho
Revaycolizer
Revaycolizer14mo ago
i didn't generate types i just gave it a thought as supabase-js supports types what if i could utilize it without generating types using supabase cli
Pitus
Pitus14mo ago
supabase gen types typescript --project-id \"YOUR_PROJECT_ID"\" --schema public > src/types/supabase.types.ts
supabase gen types typescript --project-id \"YOUR_PROJECT_ID"\" --schema public > src/types/supabase.types.ts
uhh I'm not sure which way would be the best to be honest since I don't know much about supabse-js
Revaycolizer
Revaycolizer14mo ago
oh it's okay bruh but i am really thankful with your help as i was able to get through this nightmare
Pitus
Pitus14mo ago
sure, no problem
Revaycolizer
Revaycolizer14mo ago
any idea as how i can implement middleware bruh
Pitus
Pitus14mo ago
the auth middleware?
Revaycolizer
Revaycolizer14mo ago
of course as i want to protect routes
Pitus
Pitus14mo ago
You could do a HigherOrderComponent and use my AuthContext
Revaycolizer
Revaycolizer14mo ago
then how can i attach it to my app directory
Pitus
Pitus14mo ago
and then just do
export default withAuthPContext(Page)
export default withAuthPContext(Page)
on every page that user would have to be signed in to access the page then inside the HOC you can use the useUser hook and redirect if there's no user or session (meaning thay user is logged off / user does not exist) a little tip: in app folder create (grantedAccess) folder, or (app), anything. doesnt matter but keep the naming accurate and in that folder with () around the name add layout.tsx file. and there you can use withAuthContxt HigherOrderComponent
Revaycolizer
Revaycolizer14mo ago
let me show you my app folder structure
Revaycolizer
Revaycolizer14mo ago
inside (main) i created layout.tsx
Pitus
Pitus14mo ago
yeah and now just move every page you'd want to be accessed only by signed in users you dont have to specify the name of (main) in routes, next automatically ignores it
Revaycolizer
Revaycolizer14mo ago
my layout.tsx
Pitus
Pitus14mo ago
app - (main) -- page.tsx is NOT /(main)/ it is simply / (the default route)
export default withAuthContext(RootLayout)
export default withAuthContext(RootLayout)
Revaycolizer
Revaycolizer14mo ago
is how i moved the files correctly?
Pitus
Pitus14mo ago
Make sure you didn't require to be signed in, in order to sign up or sign in other than that it should be fine
Revaycolizer
Revaycolizer14mo ago
should i use this one? the components to sign in the user are not in (main) folder
Pitus
Pitus14mo ago
yes good
Revaycolizer
Revaycolizer14mo ago
what about the component i included in the layout.tsx
Pitus
Pitus14mo ago
yeah seems good, but make sure it renders as a column and not as a row so navbar is on top and not on the side
Revaycolizer
Revaycolizer14mo ago
yes bruh it is on the top but wrapping it requires adding "use client" is it a good practice a middleware having "use client"?
Pitus
Pitus14mo ago
did you create it in app folder?
Revaycolizer
Revaycolizer14mo ago
in (main) folder here menu.tsx
Pitus
Pitus14mo ago
move it to src/utils
Revaycolizer
Revaycolizer14mo ago
menu.tsx?
Pitus
Pitus14mo ago
it's an server utility, not client the higher order component
import { redirect, usePathname } from "next/navigation";
import { useUser } from "~/providers/AuthContextProvider/AuthContextProvider";
import { api } from "~/utils/api";
import { Spinner } from "~/components/ui/spinner";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const WithPrivateRoute = (Component: React.FunctionComponent<any>) => {
const NewComponent = () => {
const { user, isLoading } = useUser();

if (isLoading) return <Spinner />;
if (!user) redirect("/unauthorized");

return <Component />;
};

return NewComponent;
};
import { redirect, usePathname } from "next/navigation";
import { useUser } from "~/providers/AuthContextProvider/AuthContextProvider";
import { api } from "~/utils/api";
import { Spinner } from "~/components/ui/spinner";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const WithPrivateRoute = (Component: React.FunctionComponent<any>) => {
const NewComponent = () => {
const { user, isLoading } = useUser();

if (isLoading) return <Spinner />;
if (!user) redirect("/unauthorized");

return <Component />;
};

return NewComponent;
};
Revaycolizer
Revaycolizer14mo ago
middleware???
Pitus
Pitus14mo ago
yes, the middleware
Revaycolizer
Revaycolizer14mo ago
what about the layout i just created? as i get confused bruh
Pitus
Pitus14mo ago
at the end of layout.tsx in (main) add:
export default WithPrivateRoute(layout);
export default WithPrivateRoute(layout);
Revaycolizer
Revaycolizer14mo ago
is this the middleware or layout?
Pitus
Pitus14mo ago
this is the middleware
Revaycolizer
Revaycolizer14mo ago
oh my bad i replaced layout.tsx with it
Pitus
Pitus14mo ago
lol
Revaycolizer
Revaycolizer14mo ago
getting AuthContext.Provider error solved as i first saved it as middleware.ts instead of middleware.tsx
Pitus
Pitus14mo ago
good
Revaycolizer
Revaycolizer14mo ago
now getting this error in layout.tsx
Pitus
Pitus14mo ago
yeah so if you actually read it you could solve it
Revaycolizer
Revaycolizer14mo ago
i was wondering as i should remove children
Pitus
Pitus14mo ago
think
Revaycolizer
Revaycolizer14mo ago
or am i making a big mistake?
Pitus
Pitus14mo ago
yes, you are
Revaycolizer
Revaycolizer14mo ago
then should i remove RootLayout?
Revaycolizer
Revaycolizer14mo ago
here
Pitus
Pitus14mo ago
think what are you trying to achieve
Revaycolizer
Revaycolizer14mo ago
protecting pages rendered in this route
Pitus
Pitus14mo ago
yeah and how would you do it
Revaycolizer
Revaycolizer14mo ago
by using middleware to restrict unauthenticated user
Pitus
Pitus14mo ago
and how do you use middelware? look at the code of WithPrivateRoute
Revaycolizer
Revaycolizer14mo ago
let me check it again this PrivateRoute where do i include it
Revaycolizer
Revaycolizer14mo ago
am i right?
Revaycolizer
Revaycolizer14mo ago
tried but getting only a spinner even if user is authenticated