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
Froxx2y 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
RevaycolizerOP2y ago
I didn't include rendering because no matter how I tried to render I got errors
uiuxphil
uiuxphil2y 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)
uiuxphil
uiuxphil2y 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.
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y 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
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y 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?
uiuxphil
uiuxphil2y ago
yes what was the error?
Revaycolizer
RevaycolizerOP2y ago
let me screenshot it now
uiuxphil
uiuxphil2y ago
also, why are you using React.FC<ProfileProps> ? the default way of making functional component would be just fine I think
Revaycolizer
RevaycolizerOP2y 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
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
this is the error i am facing
uiuxphil
uiuxphil2y ago
yeah great but let me see the error message hover over it oh yeah i think I know what are doing
Revaycolizer
RevaycolizerOP2y ago
this one throws some error
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
this one
Revaycolizer
RevaycolizerOP2y ago
should i pass a string?
uiuxphil
uiuxphil2y ago
well no wonder it cannot find ProfileProps since you commented it out. Remove comments from the interface and delete 8th line
Revaycolizer
RevaycolizerOP2y ago
done then should i try to see if the data can be displayed?
uiuxphil
uiuxphil2y ago
do you have a way of getting a type of your profile in your page.tsx?
Revaycolizer
RevaycolizerOP2y ago
thanks bruh they are retrieved successfully
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y 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
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y 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
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
oh it's okay bruh but i am really thankful with your help as i was able to get through this nightmare
uiuxphil
uiuxphil2y ago
sure, no problem
Revaycolizer
RevaycolizerOP2y ago
any idea as how i can implement middleware bruh
uiuxphil
uiuxphil2y ago
the auth middleware?
Revaycolizer
RevaycolizerOP2y ago
of course as i want to protect routes
uiuxphil
uiuxphil2y ago
You could do a HigherOrderComponent and use my AuthContext
Revaycolizer
RevaycolizerOP2y ago
then how can i attach it to my app directory
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
let me show you my app folder structure
Revaycolizer
RevaycolizerOP2y ago
inside (main) i created layout.tsx
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
my layout.tsx
uiuxphil
uiuxphil2y ago
app - (main) -- page.tsx is NOT /(main)/ it is simply / (the default route)
export default withAuthContext(RootLayout)
export default withAuthContext(RootLayout)
Revaycolizer
RevaycolizerOP2y ago
is how i moved the files correctly?
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
should i use this one? the components to sign in the user are not in (main) folder
uiuxphil
uiuxphil2y ago
yes good
Revaycolizer
RevaycolizerOP2y ago
what about the component i included in the layout.tsx
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y 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"?
uiuxphil
uiuxphil2y ago
did you create it in app folder?
Revaycolizer
RevaycolizerOP2y ago
in (main) folder here menu.tsx
uiuxphil
uiuxphil2y ago
move it to src/utils
Revaycolizer
RevaycolizerOP2y ago
menu.tsx?
uiuxphil
uiuxphil2y 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
RevaycolizerOP2y ago
middleware???
uiuxphil
uiuxphil2y ago
yes, the middleware
Revaycolizer
RevaycolizerOP2y ago
what about the layout i just created? as i get confused bruh
uiuxphil
uiuxphil2y ago
at the end of layout.tsx in (main) add:
export default WithPrivateRoute(layout);
export default WithPrivateRoute(layout);
Revaycolizer
RevaycolizerOP2y ago
is this the middleware or layout?
uiuxphil
uiuxphil2y ago
this is the middleware
Revaycolizer
RevaycolizerOP2y ago
oh my bad i replaced layout.tsx with it
uiuxphil
uiuxphil2y ago
lol
Revaycolizer
RevaycolizerOP2y ago
getting AuthContext.Provider error solved as i first saved it as middleware.ts instead of middleware.tsx
uiuxphil
uiuxphil2y ago
good
Revaycolizer
RevaycolizerOP2y ago
now getting this error in layout.tsx
uiuxphil
uiuxphil2y ago
yeah so if you actually read it you could solve it
Revaycolizer
RevaycolizerOP2y ago
i was wondering as i should remove children
uiuxphil
uiuxphil2y ago
think
Revaycolizer
RevaycolizerOP2y ago
or am i making a big mistake?
uiuxphil
uiuxphil2y ago
yes, you are
Revaycolizer
RevaycolizerOP2y ago
then should i remove RootLayout?
Revaycolizer
RevaycolizerOP2y ago
here
uiuxphil
uiuxphil2y ago
think what are you trying to achieve
Revaycolizer
RevaycolizerOP2y ago
protecting pages rendered in this route
uiuxphil
uiuxphil2y ago
yeah and how would you do it
Revaycolizer
RevaycolizerOP2y ago
by using middleware to restrict unauthenticated user
uiuxphil
uiuxphil2y ago
and how do you use middelware? look at the code of WithPrivateRoute
Revaycolizer
RevaycolizerOP2y ago
let me check it again this PrivateRoute where do i include it
Revaycolizer
RevaycolizerOP2y ago
am i right?
Revaycolizer
RevaycolizerOP2y ago
tried but getting only a spinner even if user is authenticated
Want results from more Discord servers?
Add your server