Reputation: 1180
I'm attempting to fetch the data from user once the page loads.
Although, currently when there is any route changes, it triggers my useEffect and calls the fetch user endpoint which causes my loading to trigger (is this a good approach?).
The trigger of the loading every single time annoys me and the app doesn't seem to flow since there is no need to show the loading if the user data was already fetched and the user is navigating in my app.
I believe I should setup something that will call the fetch only the first time the user loads, or if the user leaves my page and comes back. What would be a perfect approach to do so in Next.js?
This is my context, which wraps my app.
'use client'
import { User } from '@/models/user'
import { AuthService } from '@/services/auth-service'
import {
createContext,
ReactNode,
useCallback,
useEffect,
useRef,
useState,
} from 'react'
import { setCookie, destroyCookie, parseCookies } from 'nookies'
import { useRouter } from 'next/navigation'
import http from '@/utils/axios'
import { UserService } from '@/services/user-service'
import { jwtDecode } from 'jwt-decode'
import { toast } from 'sonner'
interface AuthContextType {
isAuthenticated: boolean
user: User | null
signIn: (email: string, password: string) => Promise<void>
signOut: () => void
}
interface AuthProviderProps {
children: ReactNode
}
export const AuthContext = createContext({} as AuthContextType)
export const AuthProvider = ({ children }: AuthProviderProps) => {
const router = useRouter()
const isInitialized = useRef(false)
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(false)
const isAuthenticated = !!user
const signIn = async (email: string, password: string) => {
const response = await AuthService.login(email, password)
const decodedToken = jwtDecode(response.token)
if (!decodedToken.exp) {
toast('Erro ao fazer login')
return
}
destroyCookie(undefined, 'token')
const tokenExpiration = (decodedToken?.exp * 1000 - Date.now()) / 1000
setCookie(undefined, 'token', response.token, {
maxAge: tokenExpiration,
})
http.defaults.headers.Authorization = `Bearer ${response.token}`
setUser(response.user)
router.replace('/rece')
}
const signOut = useCallback(() => {
destroyCookie(undefined, 'token')
destroyCookie(undefined, 'refreshToken')
setUser(null)
router.replace('/login')
}, [])
useEffect(() => {
if (isInitialized.current === true) return
isInitialized.current = true
setLoading(true)
const cookies = parseCookies()
const token = cookies['token']
http.defaults.headers.Authorization = `Bearer ${token}`
if (token) {
UserService.getMe()
.then((me) => {
if (me) {
setUser(me)
}
})
.finally(() => {
setLoading(false)
})
} else {
setLoading(false)
}
}, [])
if (loading) {
return <>Loading</>
}
return (
<AuthContext.Provider value={{ isAuthenticated, user, signIn, signOut }}>
{children}
</AuthContext.Provider>
)
}
I attempted to set isInitialized.current
but had no success
Upvotes: 0
Views: 29
Reputation: 1180
Apparently the issue was not in the logic, I have a sideBar from ui.shadcn
, the default redirect is with <a>
, this was causing the "issue" (not actually an issue, but for me it was), I switched to:
import { useRouter } from 'next/navigation'
const route = useRouter()
const navigate = (url: string) => {
route.push(url)
}
And it's working fine.
Upvotes: 0