I have an account page, which the user ends up after signing up. As soon as they hit this page, I would like to create a profile row with a 1-1 mapping to a (Supabase) users table.
If this would be a client side page, I would do something like this:
const ProfilePage: FC<{ userId: string }> = ({ userId }) => {
const [profile, setProfile] = useState<Profile | null>(null);
useEffect(() => {
getProfile().then(profile => {
if (profile) {
setProfile(profile)
} else {
createProfile({ user_id: userId, name: email.split("@")[0], avatar: null })
.then(setProfile)
}
})
}, [])
return profile ? (
<div>Welcome, {profile.name}</div>
) : (
<div>Loading your profile / setting up your profile ...</div>
)
}
Now I want to do this in a server component. If I understand correctly, useEffect() is a client-side hook. How do I check if something exists, run something, and make sure to re-render the page as soon as the profile has been created?
useEffect(() => {
getProfile().then(profile => {
if (profile) {
setProfile(profile)
} else {
createProfile({ user_id: userId, name: email.split("@")[0], avatar: null })
.then(setProfile)
}
})
}, [])
the code inside the useEffect is related to the supabase user. you can use createServerComponentClient on the server.
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs";
import { cookies} from "next/headers";
const getProfileByIdOrCreateProfileById = async (id: string): Promise<Profile> => {
const supabase = createServerComponentClient({
cookies: cookies,
});
const { data, error } = await supabase
.from('users')
.select('*')
.eq('id', id)
.single();
if (error) {
console.log(error.message);
}
if (data){
return (data as any) || [];
}
// your original post uses `email`. you did not post the related code where email comes from
const response= supabase.from('users').insert({ user_id: id, name: email.split("@")[0], avatar: null })
// using response return the correct value
return {response}
};
I showed the getting or creating profile in the same function. But actually using server actions would be much better to insert the profile. Example from here
import { cookies } from 'next/headers'
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
import { revalidatePath } from 'next/cache'
export default async function NewTodo() {
const addTodo = async (formData) => {
'use server'
const title = formData.get('title')
const supabase = createServerActionClient({ cookies })
await supabase.from('todos').insert({ title })
revalidatePath('/')
}
return (
<form action={addTodo}>
// in your post you are using email somehow
<input name="email" />
</form>
)
}
In this case I think just a boolean reference indicating the first render is simplest.
const ProfilePage = ({ userId }) => {
const [profile, setProfile] = useState(null);
const firstRender = useRef(true);
if (firstRender.current) {
firstRender.current = false;
getProfile(userId).then((profile) => {
if (profile) {
setProfile(profile);
} else {
createProfile({
user_id: userId,
name: email.split('@')[0],
avatar: null,
}).then(setProfile);
}
});
}
return profile ? (
<div>Welcome, {profile.name}</div>
) : (
<div>Loading your profile / setting up your profile ...</div>
);
};
Demo: https://stackblitz.com/edit/stackblitz-starters-d3z6hx?file=pages%2Fprofile.tsx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With