I'm new to React and I'm trying to understand how to do things in the right way. So I have a Navbar that displays different links based on if a user is logged in or not. If a user logs in i set a cookie loggedIn=true
. Than in my Navbar ponent, I check for these cookies with window.setInterval
:
import React, { Component } from 'react'
import { NavLink, Link } from "react-router-dom"
import styles from './Navbar.module.css'
class Navbar extends Component {
constructor() {
super()
this.state = {
loggedIn: false
}
}
ponentDidMount() {
if (document.cookie.split(';').filter((item) => item.trim().startsWith('logedIn=')).length) {
this.setState({ loggedIn: true })
}
window.setInterval(() => {
if (document.cookie.split(';').filter((item) => item.trim().startsWith('logedIn=')).length) {
this.setState({ loggedIn: true })
}
else {
this.setState({ loggedIn: false })
}
}, 500)
}
render() {
return (
<header>
<nav className={` ${styles.navbar} navbar navbar-dark bg-dark navbar-expand-lg`}>
<div className='container'>
<Link className='navbar-brand mr-5' to='/'>I <i className={`${styles.red} fas fa-heart fa-xs`}></i> Jokes</Link>
<button className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarContent"
aria-controls="navbarContent"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarContent">
<ul className="navbar-nav mr-auto">
<li className="nav-item ">
<NavLink className="nav-link" exact to="/">Home</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/about">About</NavLink>
</li>
</ul>
<ul className="navbar-nav">
{this.state.loggedIn ?
<React.Fragment>
<NavLink className="nav-link mr-3" to="/myaccount">My account</NavLink>
<NavLink className='nav-link' to='/logout'>Log out</NavLink>
</React.Fragment>
:
<React.Fragment>
<NavLink className='nav-link mr-3 ' to='/login'>Log in</NavLink>
<NavLink className='nav-link' to='/signup'>Sign up</NavLink>
</React.Fragment>
}
</ul>
</div>
</div>
</nav>
</header>
)
}
}
export default Navbar
Here is my App ponent:
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import Navbar from './ponents/Navbar/Navbar'
import Footer from './ponents/Footer/Footer'
import Home from './ponents/Home/Home'
import About from './ponents/About/About'
import SignUp from './ponents/SignUp/SignUp'
import LogIn from './ponents/LogIn/LogIn'
import UserAccount from './ponents/UserAccount/UserAccount'
import './App.css'
function App() {
return (
<div className="App">
<Navbar />
<Switch>
<Route exact path='/about' ponent={About} />
<Route exact path='/signup' ponent={SignUp} />
<Route exact path='/login' ponent={LogIn} />
<Route exact path='/account' ponent={UserAccount}/>
<Route exact path='/' ponent={Home} />
</Switch>
<Footer />
</div>
);
}
export default App;
I feel like it's a wrong way to do it, and I'd like to get pointers on how to do it properly. Thanks!
I'm new to React and I'm trying to understand how to do things in the right way. So I have a Navbar that displays different links based on if a user is logged in or not. If a user logs in i set a cookie loggedIn=true
. Than in my Navbar ponent, I check for these cookies with window.setInterval
:
import React, { Component } from 'react'
import { NavLink, Link } from "react-router-dom"
import styles from './Navbar.module.css'
class Navbar extends Component {
constructor() {
super()
this.state = {
loggedIn: false
}
}
ponentDidMount() {
if (document.cookie.split(';').filter((item) => item.trim().startsWith('logedIn=')).length) {
this.setState({ loggedIn: true })
}
window.setInterval(() => {
if (document.cookie.split(';').filter((item) => item.trim().startsWith('logedIn=')).length) {
this.setState({ loggedIn: true })
}
else {
this.setState({ loggedIn: false })
}
}, 500)
}
render() {
return (
<header>
<nav className={` ${styles.navbar} navbar navbar-dark bg-dark navbar-expand-lg`}>
<div className='container'>
<Link className='navbar-brand mr-5' to='/'>I <i className={`${styles.red} fas fa-heart fa-xs`}></i> Jokes</Link>
<button className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarContent"
aria-controls="navbarContent"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarContent">
<ul className="navbar-nav mr-auto">
<li className="nav-item ">
<NavLink className="nav-link" exact to="/">Home</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/about">About</NavLink>
</li>
</ul>
<ul className="navbar-nav">
{this.state.loggedIn ?
<React.Fragment>
<NavLink className="nav-link mr-3" to="/myaccount">My account</NavLink>
<NavLink className='nav-link' to='/logout'>Log out</NavLink>
</React.Fragment>
:
<React.Fragment>
<NavLink className='nav-link mr-3 ' to='/login'>Log in</NavLink>
<NavLink className='nav-link' to='/signup'>Sign up</NavLink>
</React.Fragment>
}
</ul>
</div>
</div>
</nav>
</header>
)
}
}
export default Navbar
Here is my App ponent:
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import Navbar from './ponents/Navbar/Navbar'
import Footer from './ponents/Footer/Footer'
import Home from './ponents/Home/Home'
import About from './ponents/About/About'
import SignUp from './ponents/SignUp/SignUp'
import LogIn from './ponents/LogIn/LogIn'
import UserAccount from './ponents/UserAccount/UserAccount'
import './App.css'
function App() {
return (
<div className="App">
<Navbar />
<Switch>
<Route exact path='/about' ponent={About} />
<Route exact path='/signup' ponent={SignUp} />
<Route exact path='/login' ponent={LogIn} />
<Route exact path='/account' ponent={UserAccount}/>
<Route exact path='/' ponent={Home} />
</Switch>
<Footer />
</div>
);
}
export default App;
I feel like it's a wrong way to do it, and I'd like to get pointers on how to do it properly. Thanks!
Share Improve this question edited Jul 27, 2019 at 14:33 Shubham Verma 5,0541 gold badge10 silver badges22 bronze badges asked Jul 27, 2019 at 14:16 NoobNoob 2,8074 gold badges23 silver badges43 bronze badges 2- 2 Maybe this help : kentcdodds./blog/authentication-in-react-applications – Shubham Verma Commented Jul 27, 2019 at 14:29
- 1 small hint '<React.Fragment></React.Fragment>' can be used via shortcut '<></>' link to react docs – Oleg Lozynskyi Commented Jul 27, 2019 at 14:33
3 Answers
Reset to default 3I would remend Lifting State Up in this case:
function App() {
const [loggedIn, setLoggedIn] = useState(
// initial value
document.cookie.split(';').some((item) => item.trim().startsWith('logedIn=')));
return (
<div className="App">
<Navbar {...{loggedIn}} />
<Switch>
<Route exact path='/about' ponent={About} />
<Route exact path='/signup' ponent={SignUp} />
<Route exact path='/login' render={
(routeProps) => <LogIn {...{setLoggedIn, ...routeProps}} />
} />
<Route exact path='/account' ponent={UserAccount}/>
<Route exact path='/' ponent={Home} />
</Switch>
<Footer />
</div>
);
}
and use the additional props in Navbar
and LogIn
ponents (cookies only used when reloading the page for the initial state above, not inside Navbar):
fucntion Navbar(props) {
return (
<header>
...
{props.loggedIn ? ... // instead of this.state.loggedIn
)
}
- You shouldn't duplicate a lot of code a believe you can change the links in a better way like this:
render() { const link1 = this.state.loggedIn ? '/myaccount' : '/login'; const link1 = this.state.loggedIn ? '/logout' : '/signup'; return ( ... <ul className="navbar-nav"> <NavLink className="nav-link mr-3" to={link1}>My account</NavLink> <NavLink className='nav-link' to={link2}>Log out</NavLink> </ul> ) }
- Not fully understand why you check if user logged in through cookies, maybe there is better option as JWT autorization ? here is a link
Checking whether a user is logged in is probably out of the scope of this question, but you seem to be handling it anyway.
As you cannot use if statements in JSX, the two accepted ways to conditionally render JSX based on certain values is either via a ternary operator or a switch statement if you have multiple conditions to check against.
An example of using a ternary operator would be when you need to render a different navbar based on whether a user is logged in or not.
An example of when you would use a switch statement would be when you had multiple user roles and each of them needed to see a different iteration of a navbar.