Next.js Discord

Discord Forum

how do i trigger loading state to fix conditional flickering?

Answered
HOTCONQUEROR posted this in #help-forum
Open in Discord
my login page:
"use client";
import { useState,useEffect,useContext} from "react";
import {redirect, useRouter} from 'next/navigation'
import { AuthContext } from "../provider";
function Login(){

    const isAuth = useContext(AuthContext)

    interface LoginStruct {
        email: string,
        password: string
    }
    const [error,setError] = useState('')



    const [loginInfo, setLoginInfo] = useState<LoginStruct>({email:'',password:''})
    const route = useRouter()
    console.log(isAuth)

    const handleLogout = ()=>{
        fetch("http://127.0.0.1:8000/logout/",{method:'POST',credentials:'include'}).then((res)=>{
            res.json().then((data)=>{
                if(data?.success){
                    route.refresh()

                }
                if(data?.error){
                    setError(data?.error)
        
                    
                }
            })

        })


    }
    const handleChange = (e:any):void=>{
        setLoginInfo({...loginInfo, [e.target.name]:e.target.value})
    }


    const handleSubmit = (e:any):void=>{
        e.preventDefault()
        fetch('http://127.0.0.1:8000/login/',{method:'POST',body:JSON.stringify(loginInfo),credentials:'include', headers:{'Content-Type':'application/json'}}).then((res)=>{
            if(res.status == 200){
                route.replace('/login')



            }

            else{
                setError('wrong credinitials')
            }
        })
    }


...
Answered by Arinji
You can't use context in a server component
View full answer

83 Replies

    if(!isAuth.status){
        
    return(
    <div className='loginPage'>
        <div className='loginContainer'>
            <form className="loginForm" onSubmit = {handleSubmit} method='post'>
                <input type='text' className='email' name='email' value={loginInfo.email} placeholder='Enter your email' onChange={handleChange}/>
                <input type='password' className='password' name='password' value={loginInfo.password} placeholder='Enter your password' onChange={handleChange}/>
                <button type='submit' className='loginBtn'>Login</button>
                <div className="error">{error}</div>

            </form>
        </div>
    </div>
    )
    }
    return <div className='alrAuth'>You are already logged in!
    <div>Do you want to log out? <button onClick={handleLogout}>Logout</button></div>
    </div>

}

export default Login

cause word limit
and my loading.tsx now:
import { Suspense } from "react"
export default function LoginLoadin(){
    return <div className='skeleton'>Loading...</div>
}
however i am still getting flickering between being in non-authenticated state to being in auth state in a second, but i want to trigger loading state instead of flickering?
@HOTCONQUEROR could you record what's happening


Also can you clear out extra stuff like styling and form fields.. it's hard to look at what's actually happening
basically a flickering happen based on the condition i guess
@Arinji if you need more info please tell
ok so apparently loading.js only work on navigating (moving between pages)
but on reload? this is where the flickering problem occur
@HOTCONQUEROR ok so apparently `loading.js` only work on navigating (moving between pages)
Yup, loading.js is only shown when navigating though pages.
@Arinji Yup, loading.js is only shown when navigating though pages.
i just re-read documents on it
but how do i fix that on reloading tho
@Arinji Is this your page.jsx?
yes
Thats the issue then, it's not a nextjs thing. It's react.
@Arinji Thats the issue then, it's not a nextjs thing. It's react.
it is client component, so i guess so
Another thing I need clarified. What's the default state.. the logged out message right?
The stuff before you check if the user is auth.. like when you are initializing
@Arinji Another thing I need clarified. What's the default state.. the logged out message right?
default state in the context is not authintecated
not auth
@HOTCONQUEROR default state in the context is not authintecated
So then that's the issue
@Arinji So then that's the issue
it has to be null?
How it goes is first the initial stuff is shown.. that would be your not authenticated ui
Then react hydrates the page, and it shows the auth ui
And that gap, is the flickering
do i nullify it?
@Arinji And that gap, is the flickering
make sense
Not really.. don't make a page client
@Arinji Not really.. don't make a page client
um, how do except me to use hooks then
Make a different component for client stuff
@HOTCONQUEROR what is next?
Do the fetching in the page file on the server
And make the ui wait for that.
That will make sure that only the correct ui is shown on render
@Arinji Do the fetching in the page file on the server
wait, what do you mean by "do the fetching"?
@HOTCONQUEROR wait, what do you mean by "do the fetching"?
Do fetch calls on the server
Get requests
@Arinji Get requests
but that require useEffect tho?
using handleSubmit and handleChange need a client component too
event handlers are only to be used in client components
Do you store the auth somewhere? Or is a login once and then login the next time you open the site
Ok so you can read cookies in the page itself
If you see auth.. show the auth ui.. inside the page file
Else show the not auth ui
When you login.. make the form do a router.refresh()
That will make the page get cookies again and this time show auth
@Arinji Else show the not auth ui
oh so you want me to do the conditional rendering on page.tsx, but the client part of the component on different file?
The form in the different file with the use client on top of the file
And you call that component in the different file front your page.tsx
@Arinji Yes
but i don't think i can import that component to page, if page is server component, no?
Server components can call client components inside them as many times as you want
No restrictions
Client components can't call server components (atleast not the normal way)
i remember getting error about that, but i will try
and will come back to you.
Sure
Also just ping once..
@Arinji Also just ping once..
"use client";
import { useState,useEffect,useContext} from "react";
import {redirect, useRouter} from 'next/navigation'
import { AuthContext } from "../src/app/provider";
import Link from 'next/link';




function Login(){


    interface LoginStruct {
        email: string,
        password: string
    }
    const [error,setError] = useState('')



    const [loginInfo, setLoginInfo] = useState<LoginStruct>({email:'',password:''})
    const route = useRouter()

    
    const handleChange = (e:any):void=>{
        setLoginInfo({...loginInfo, [e.target.name]:e.target.value})
    }


    const handleSubmit = (e:any):void=>{
        e.preventDefault()
        fetch('http://127.0.0.1:8000/login/',{method:'POST',body:JSON.stringify(loginInfo),credentials:'include', headers:{'Content-Type':'application/json'}}).then((res)=>{
            if(res.status == 200){
                route.push('/')



            }

            else{
                setError('wrong credinitials')
            }
        })
    }


    
    return( 
    <div className='loginPage'>
        <div className='loginContainer'>
            <form className="loginForm" onSubmit = {handleSubmit} method='post'>
                <input type='text' className='email' name='email' value={loginInfo.email} placeholder='Enter your email' onChange={handleChange}/>
                <input type='password' className='password' name='password' value={loginInfo.password} placeholder='Enter your password' onChange={handleChange}/>
                <button type='submit' className='loginBtn'>Login</button>
                <div className="error">{error}</div>
                <Link href='/notes'>Test loading component.</Link>

            </form>
        </div>
    </div>
    )
}
export default Login;

Login component ^
the page.tsx, i get error because i am using useContext which is react hook
function LoginPage(){

    const isAuth = useContext(AuthContext)

    return(
    !isAuth.status? 
    <Login></Login>
    :
     <div className='alrAuth'>You are already logged in!
    <div>Do you want to log out? <button >Logout</button></div>
    <Link href='/notes'>Test loading component.</Link>
    </div>
    )



}

export default LoginPage;
Well..why are you using useContext...
@Arinji Well..why are you using useContext...
I actually didn't quite catch what you wanted to say tbh
should i do the conditional rendering also in the component?
@HOTCONQUEROR I actually didn't quite catch what you wanted to say tbh
See, context is again.. react.
What are you doing inside your context... I'm assuming you fetch the auth data and check if they are authenticated?
@HOTCONQUEROR yes.
Ok so assume this

Inside your context you fetch to an api so

await fetch()

Now instead of fetching on the client. What you would do is take the fetch call and any related data... Put it in its own function and don't use it inside context..but directly in the page
So await getData()
Use that in any page you need auth data
Go through this, it's what I just said but better explaindd
@Arinji So await getData() Use that in any page you need auth data
but that would literally mean i will sacrifice react context

the whole reason i am using react context is to invest in the number of requests per page

so, instead of checking that user is authenticated in every route, you just use context as a way to share a global state among all pages
which means the request happen once and the state of that request is shared among all routes
@Arinji That's the whole thing, you use a middleware to check all requests.. or do a cached function
i mean, i do have middleware in the backend for that, but you still need to check in the frontend on every page since you need to send request to know if user is auth or not.
@HOTCONQUEROR i mean, i do have middleware in the backend for that, but you still need to check in the frontend on every page since you need to send request to know if user is auth or not.
Well if you already have a function you use in the middle ware to check auth.. call the same function in all the pages you need auth
You can't use context in a server component
Answer