In my React App, when the user logins, a token is generated (JWT) after that it is stored in LocalStorage.
Once everything is done, in order to maintain user login for different routes, I'm using useContext.
I want to show logout button if the user is logged in (in reality it appears, but after 2 seconds) in short, I could see login / register button and after 2 seconds it shows the logout button.
Here is my code:
Main.js
export default function Main() {
const [userData,setUserData] = useState(
{token:undefined,
user:undefined,}
);
useEffect(()=>{
const checkLoggedIn = async() =>{
const token = localStorage.getItem("auth-token");
if(token===null) {localStorage.setItem("auth-token","");
token = "";}
const tokenRes = await Axios.post("http://localhost:5000/user/tokenIsValid",
null,
{headers:{"x-auth-token":token}})
if(tokenRes.data){
const userRes = await Axios.get("http://localhost:5000/user/",{headers:{"x-auth-token":token}})
setUserData({
token,
user:userRes.data
})
}
};
checkLoggedIn();
}
,[])
return (
<BrowserRouter>
<UserContext.Provider value={{userData,setUserData}}>
<ThemeProvider theme={theme}>
<Navbar />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
<Route exact path="/recover" component={Recover} />
<Route exact path="/privacy-policy" component={PrivacyPolicy} />
<Route
exact
path="/terms-of-service"
component={TermsAndConditions}
/>
<Route exact path="/contact" component={Contact} />
<Route exact path="/faqs" component={FAQs} />
<Route component={Error} />
</Switch>
<myFooter />
</ThemeProvider>
</UserContext.Provider>
</BrowserRouter>
);
}
Then here is my Navbar.js
export default function Navbar(){
const { userData,setUserData } = useContext(UserContext);
const classes = useStyles();
const logout = () =>{
setUserData({
token:undefined,
user:undefined
})
localStorage.setItem("auth-token","")
}
return(
<>
<AppBar position="static" color="transparent">
<Toolbar>
<Typography className={classes.doBold}>
<Link to="/" className={classes.noLinkStyle}><img src={require('../images/logo.png')} height="auto" width="150px" className={classes.AlignVertical} alt="Logo"/></Link>
</Typography>
<ButtonGroup size="small" variant="outlined" color="secondary">
{
userData.user!==undefined?<myLoginMenu style={{marginRight:'20px'}}/>:<> <Link to="/login" className={classes.noLinkStyle}><myButton variant="contained" content="Login" icon="login"/></Link>
<Link to="/register" className={classes.noLinkStyle}><myButton variant="contained" primary content="Register" icon="register" /></Link></>
}
</ButtonGroup>
</Toolbar>
</AppBar>
</>
)
}
And at last UserContext.js
import {createContext} from 'react';
export default createContext(null);
And here is my Login Route
router.get("/login", async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ msg: "Something is missing." });
}
const student = await Student.findOne({ email: email });
if (!student)
return res
.status(400)
.json({ msg: "No account reigstered with this email." });
const isMatch = await bcrypt.compare(password, student.password);
if (isMatch) {
const token = jwt.sign({id:student._id},process.env.JWT_TOKEN)
res.json({
token,
user:{
id:student._id
}
})
} else return res.status(400).json({ msg: "Incorrect Password" });
} catch (error) {
res.status(500).json({ errorReceived: error });
}
});
Edited: Sorry I didn't read your question well. Yes, what you're facing is quite normal because at the first render, you're not logged in so the Log out button would appear to be Log in.
What you can do is:
Log in/Log out button until the useEffect finishes running) so the user's experience would be more smooth.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With