I am developing a system, that system has login function and it is working successfully. That login process takes username and role. When I check it on Login.jsx it is fine, I can see role and username correctly. The problem is that I have a Sidebar component and I want to render that sidebar after successfull login, not before login. When I check username and role inside App.js, they are undefined. Why is that happening. Btw, If I add Sidebar without conditional rendering, I can see 3 different Sidebar for 3 users, I can set it using roles. I believe it happens because Login and Sidebar are on the same hierarchy. Please help me
AuthProvider.js:
import { createContext, useState } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState({
username: null,
password: null,
role: null,
accessToken: null,
});
const login = ({ username, password, role, accessToken }) => {
setAuth({
username,
password,
role,
accessToken,
})
}
const logout = () => {
setAuth({
username: null,
password: null,
role: null,
accessToken: null,
})
}
return (
<AuthContext.Provider value={{ auth, setAuth, login, logout }}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext;
Login.jsx:
import React, { useEffect, useState, useRef } from 'react';
import { useNavigate, Link, useLocation } from 'react-router-dom'; // Import useNavigate
import useAuth from './hooks/useAuth';
// Img
import LoginBg from "../assets/img/upg-bg.jpg";
const Login = (props) => {
const { setAuth, login } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || "/";
const userRef = useRef();
const errRef = useRef();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errMsg, setErrMsg] = useState("");
// const { login } = useAuth();
const handleLogin = async (e) => {
e.preventDefault();
try {
const response = await fetch(`some url in here`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ username, password }),
})
const data = await response.json();
const role = data.role[0].roleName;
const accessToken = data.token;
console.log("role from login", role)
// login(data.token, data.role[0].roleName);
// setAuth({ username, password, role, accesToken })
login({
username: username,
password: password,
role: role,
accessToken: accessToken,
})
setUsername("");
setPassword("");
navigate("/", { replace: true });
} catch (error) {
if (error.response?.status === 400) {
setErrMsg("Yanlış kullanıcı adı ya da şifre!");
} else if (error.response?.status === 401) {
setErrMsg("Yetkiniz Yok!");
} else {
setErrMsg("Giriş başarısız!");
}
errRef.current?.focus();
}
}
// To login on press Enter
const handleKeyPress = e => {
if (e.keyCode === 13) {
handleLogin();
}
}
useEffect(() => {
userRef.current?.focus();
}, [])
useEffect(() => {
setErrMsg("");
}, [username, password])
useEffect(() => {
console.log("user context updated", login)
}, [login])
return (
<div onKeyDown={handleKeyPress} id='login-page' className=' absolute z-30 w-screen h-screen'>
// some divs etc...
</div>
)
}
export default Login
App.js:
import React, { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { AuthProvider } from "./components/auth/AuthProvider";
import Login from "./components/Login";
import Sidebar from "./components/Sidebar";
function App() {
const { auth, login } = useAuth();
console.log("role from app", auth?.role)
console.log("login", login.role)
return (
<AuthProvider>
<div className="App">
<Routes>
<Route path="/login" element={<Login />} />
</Routes>
<div className="flex">
{auth?.role === 'admin' && <Sidebar />}
</div>
</div>
</AuthProvider>
)
}
Sidebar.jsx:
import React from 'react'
import { Link } from 'react-router-dom';
import useAuth from './hooks/useAuth';
import { MdTableView, MdOutlineLogout } from 'react-icons/md';
import { AiOutlineQuestionCircle, AiOutlinePlusCircle } from 'react-icons/ai';
import { TbCircleLetterC } from 'react-icons/tb';
const Sidebar = (props) => {
const { auth } = useAuth();
const logOut = () => {
// props.setIsLoggedIn(false);
}
const sidebarSelect = (id) => {
const link = document.getElementById(id);
// Deselect link if there is any
const previouslySelectedLinks = document.querySelectorAll(".selected");
previouslySelectedLinks.forEach((div) => {
div.classList?.remove("selected", "bg-zinc-600");
div.classList?.add("hover:bg-zinc-600");
});
// Select new link
link.classList?.add("bg-zinc-600", "selected");
link.classList?.remove("hover:bg-zinc-600");
}
return (
<div id="sidebar" className='flex-none bg-gradient-to-b from-zinc-700 to-zinc-900 fixed w-full top-0 bottom-0 max-w-[16rem] -ms-[16.5rem] md:ms-3 my-3 rounded-lg text-white duration-300 z-10'>
<div id="sidebar-header" className='py-6 text-center'>
{/* <Link to="/">
</Link> */}
<h1 id='sidebar-title' className='font-bold'>İstanbul Medeniyet Universitesi</h1>
</div>
<hr className='mx-4' />
<div className='py-6 mx-4'>
<ul className='flex flex-col'>
{auth?.role === 'admin' && (<Link id='0' onClick={() => sidebarSelect(0)} to="/admin-dashboard" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300'> <MdTableView size={25} /> Admin Paneli</Link>)}
<Link id='1' onClick={() => sidebarSelect(1)} to="/" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2 selected bg-zinc-600'> <AiOutlineQuestionCircle size={25} /> Birim Sorular</Link>
{(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='2' onClick={() => sidebarSelect(2)} to="/upg-soru-ekle" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'>
<div className='relative'>
<AiOutlineQuestionCircle size={25} />
<AiOutlinePlusCircle className='absolute top-3 -right-1 rounded-full bg-zinc-700 ' size={15} />
</div>
UPG Soru Ekle</Link>)}
{(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='3' onClick={() => sidebarSelect(3)} to="/upg-cevaplar" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'> <TbCircleLetterC size={25} />UPG Cevaplar</Link>)}
{(auth.role === 'admin' || auth?.role === 'upg') && (<Link id='4' onClick={() => sidebarSelect(4)} to="/upg-cevap-basligi-ekle" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'>
<div className='relative'>
<TbCircleLetterC size={25} />
<AiOutlinePlusCircle className='absolute top-3 -right-1 rounded-full bg-zinc-700 ' size={15} />
</div>
UPG Cevap Başlığı Ekle</Link>)}
{/* <Link id='5' onClick={() => { logOut(); }} to="/" className='flex items-center gap-2 hover:bg-zinc-600 p-2 rounded-lg duration-300 mt-2'> <MdOutlineLogout size={25} /> Çıkış Yap</Link> */}
<Logout />
</ul>
</div>
</div>
)
}
I try to get username and role after immediately log in
2
Answers
I added my Sidebar inside AuthProvider, that fixed my problem, I can see Sidebar after I login system
It seems
useAuth
hook is callinguseContext(AuthContext)
internally. If it is true, it means you are trying to getAuthContext
outside ofAuthProvider
in App.js. As a result, you get a default value of the context, which is an empty object{}
, and getundefined
for its properties. To solve this problem, I think you should find a way to calluseAuth
underAuthProvider
. Below is a simple version of what I think your code should be.