Search code examples
reactjsreact-google-login

Unwanted delay displaying user name and profile picture in React


I have a web page/app written in React that has two components, main page and a navigation bar at the top of the page. The navigation bar has a Google login button component that allows the user to log in with their Google account. When the user logs in, the navigation bar also has a component that shows the user name and profile picture. Here is an example screenshot:

Imgur

The problem is that when the user navigates to other pages, the avatar and text always take about a second to show up, making the page navigation janky.

When the user navigates to other page, the user avatar and name take a second to show up. This causes everything else on the page to suddenly move downwards.

Here's some parts of the code: App.js

const App = () => {
    return(
        <div>
            <Navigation/>
            <Routes>
                <Route path="/" element={<Landing/>} />
                <Route path="/extrainfo" element={<ExtraInfo/>} />
                <Route path="/test" element={<Test/>}/>
                <Route path="/userpage" element={<Userpage/>}/>
            </Routes>
        </div>
            
    );
}

Navigation.js

const Navigation = () => {
    let userInfo = JSON.parse( localStorage.getItem('userInfo') );

    const [isLoggedIn, setIsLoggedIn] = useState(false);
    const navigate = useNavigate();

    const onSuccess = async (googleRes) => {
        localStorage.setItem("user", JSON.stringify(googleRes));
        setIsLoggedIn(true);
        
        try{
            let userResponse = await UserService.getUser()
            if(userResponse.status === 200){
                
                setIsLoggedIn(true);
                navigate("/userpage");
            } 
        }
        catch(error){
            if (error.response.status === 404){
                /* navigate("/extrainfo"); */
            }
            const resMessage = (error.response && error.response.data && error.response.data.message) || error.message || error.toString();
            console.log(resMessage);
        }
    };

    const onFailure = (err) => {
        console.log('failed', err);
    };

    const onLogout = (res) => {
        console.log("log out");
        UserService.logout();
        setIsLoggedIn(false);
    }

    useEffect(() => {
        document.title = 'Navigation';   

        const start = () =>{
            gapi.client.init({
                clientId: process.env.REACT_APP_GOOGLE_CLIENT_ID,
                scope: 'email',
            });
        }
        gapi.load('client:auth2', start);

    }, []);

    return (
        <nav className="dt w-100 border-box pa2 ph5-ns bg-#f5f5f5">
            <a href="/" title="Home">
                <img src="mylogo.png" 
                    className="dib w3 h3 br-100" alt="Site Name"/>
            </a>
            <div className="dtc v-mid w-40 tr">
                { isLoggedIn ? (
                    <GoogleLogout
                    clientId= {process.env.REACT_APP_GOOGLE_CLIENT_ID}
                    buttonText="Logout"
                    onLogoutSuccess={onLogout}
                />) : (
                    <GoogleLogin 
                    clientId= {process.env.REACT_APP_GOOGLE_CLIENT_ID}
                    buttonText="Sign in"
                    onSuccess={onSuccess}
                    onFailure={onFailure}
                    cookiePolicy={'single_host_origin'}
                    isSignedIn={true}
                />
                )}
            </div>
            <div className="dtc v-mid w-10 tr">
                <a className="link dim white f6 f5-ns dib mr3 mr4-ns bg-dark-gray pa2" href="landing" title="Landing">Enter page</a>
            </div>
            <MyAvatar isLoggedIn={isLoggedIn}/>
        </nav>
    );
} 

MyAvatar.js

const MyAvatar = (isLoggedIn) => {
    const usrData = JSON.parse( localStorage.getItem('user') );
    let usrObj = {};
    let usrName = null;
    let usrImg = null;
    
    if (usrData) {
        usrObj = usrData['profileObj'];
        usrName = usrObj['name'];
        usrImg = usrObj['imageUrl'];
    }
    
    if(isLoggedIn.isLoggedIn === true ){
        return(
            <div className="dtc v-mid w-10 pa1 tc">
                <img
                    src={usrImg}
                    className="br-100 h3 w3 dib" alt={usrName + ' avatar'}>
                </img>
                <p className="avatar_name">{usrName}</p>
            </div>
        )
    }
    
}

Solution

  • it seems like the information tooks a bit longer then the rest to load. Usually if you would use a styling library, you could use skeletons. These elements are like placeholders which are shown until the data is loaded properly. You see them for example in many social media apps, when new content is loading but not displayed yet. But this is a intermediate thing to learn.

    What could be more helpful in your case, is to move the loading part of your app from the navigation component into the main App. By this, you prevent a new loading everytime the Navigation element is rendered, which I assume causes the delay. Or, even better would be a function which is only called when someone clicks the login button.

    You should have a look at stores also. I assume you're learning the basics, so stores will cross your ways sooner or later, but for your case, they are pretty good, since you can access them from everywhere and don't have to deal with propdrilling.

    Just put the Userdata in a store and acess the store in the Navigation element. That should do the trick. Have a nice day and keep on learning.