I'm trying to build a code that, depending on the result coming from the Hook, redirects to a different page.
So my hook uses the code below:
import { useEffect, useState } from "react"
import { database } from "../../services/firebase"
type UserDetails = {
id: string,
userID: string,
userName: string,
userEmail: string,
userAvatar: string,
userDescription: string,
userSkills: string,
userPhone: string,
userTitle: string,
userInterests: string
}
export function useGetUserProfile(userid: string | undefined){
const [ userDef, setUserDef ] = useState<UserDetails>()
const [ loading, setLoading ] = useState<boolean>(true)
useEffect(()=>{
const userRef = database.ref(`users/${userid}`);
userRef.on('value', userInfo =>{
const databaseUser = userInfo.val();
const userDetails: UserDetails = {
id: databaseUser.key,
userID: databaseUser.userID,
userName: databaseUser.userName,
userEmail: databaseUser.userEmail,
userAvatar: databaseUser.userAvatar,
userDescription: databaseUser.userDescription,
userSkills: databaseUser.userSkills,
userPhone: databaseUser.userPhone,
userTitle: databaseUser.userTitle,
userInterests: databaseUser.userInterests
}
setUserDef(userDetails);
setLoading(false);
})
},[userid])
return{userDef, loading}
}
And here is my page function:
const [ userId, setUserID ] = useState<string | undefined>("")
const { userDef, loading } = useGetUserProfile(userId)
async function handleAuthGoogle(){
if(!user){
await singIngWithGoogle();
}
if(!loading){
await setUserID(user?.id)
if(userDef != undefined){
navigate('/home');
}else{
navigate(`/Profile/Editar/${userId}`)
}
}
}
The function completes before the hook loads. My question is, how do I code it in order to wait the hook completes loading to then run the function? I tried using while, but didn't work well.
CodePudding user response:
A component that has useGetUserProfile cannot be loaded until you have access to userId.
const Page = () => {
const [ userId, setUserID ] = useState<string | undefined>("");
async function handleAuthGoogle(){
if(!user){
await singIngWithGoogle();
}
setUserID(user?.id)
}
useEffect(() => handleAuthGoogle(), []);
return userId ? <SignInRouter userId={userId} /> : <Whatever />;
}
// And then
const SignInRouter = ({ userId }) => {
const { userDef, loading } = useGetUserProfile(userId);
useEffect(() => {
if (!loading && userDef) navigate('');
else navigate('');
}, [loading, userDef]);
}
Or update the hook to react to userId becoming available.
export function useGetUserProfile(userid: string | undefined){
const [ userDef, setUserDef ] = useState<UserDetails>()
const [ loading, setLoading ] = useState<boolean>(true)
useEffect(()=>{
// Don't attempt a fetch until an id is available
if (!userid) return;
// rest of stuff
},[userid])
return{userDef, loading}
}
CodePudding user response:
I think your function useGetUserProfile()
will return undefined before it's set. As a solution:
- I'd suggest you consider a Promise-based return from the
useGetUserProfile()
function. and get it in your main component with.then()
. - you need to catch it if it's
undefined
or rejected.
As reference here is the sample code:
// Getter
const GetUserData =(userid: string | undefined):Promise<any> => {
const [ userDef, setUserDef ] = useState<UserDetails>()
const [ loading, setLoading ] = useState<boolean>(true)
return new Promise((resolve,reject)=>{
const userRef = database.ref(`users/${userid}`);
// if we NOT got all data needed
if(userRef===undefined){
setLoading(false);
reject("user not found")
}
else{
userRef.on('value', userInfo =>{
const databaseUser = userInfo.val();
const userDetails: UserDetails = {
id: databaseUser.key,
userID: databaseUser.userID,
userName: databaseUser.userName,
userEmail: databaseUser.userEmail,
userAvatar: databaseUser.userAvatar,
userDescription: databaseUser.userDescription,
userSkills: databaseUser.userSkills,
userPhone: databaseUser.userPhone,
userTitle: databaseUser.userTitle,
userInterests: databaseUser.userInterests
}
setLoading(false);
resolve(userDetails);
}
})
}
And you would call it from the main component like this:
const [userId, setUserID] = useState<string | undefined>("");
const { userDef, loading } = useGetUserProfile(userId);
async function handleAuthGoogle() {
if (!user) {
await singIngWithGoogle();
}
GetUserData(user?.id).then(response=>{
navigate(`/Profile/Editar/${userId}`);
}).catch(e=>{
console.log(e)
navigate("/home");
})
}