Home > Software engineering >  How run function after the hook completes?
How run function after the hook completes?

Time:06-27

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:

  1. I'd suggest you consider a Promise-based return from the useGetUserProfile() function. and get it in your main component with .then().
  2. 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");
  })
  
}
  • Related