如果用户登录或未登录,实现条件导航栏的策略
Posted
技术标签:
【中文标题】如果用户登录或未登录,实现条件导航栏的策略【英文标题】:Strategies to implementing a conditional Navbar if a user is logged in or not 【发布时间】:2020-08-08 10:33:05 【问题描述】:背景:我正在创建一个非常基本的应用程序,它具有 4 种不同的功能:注册、登录、搜索和创建内容。截至目前,我可以登录用户并防止未经授权的用户进入受保护的路线。这在我的Protected.js
组件中如下所示。但是,我正在努力寻找一种方法来在位于我的App.js
的导航栏中有条件地显示登录/注销按钮。
后续问题:我是否应该将身份验证逻辑从我的Login.js
路由中移到我的主要App.js
组件中并传递状态?那不是非常低效吗,因为每次我渲染一个新视图时,App.js
都会使用我的后端 API 执行另一个提取来验证用户是否有一个未过期的会话?这对某些人来说可能看起来微不足道,但我很难思考如何有效地有条件地显示登录/注销按钮。我已经研究过 Context API,所以如果你觉得有必要,我愿意接受一些建议,但我对 Redux 不熟悉(我一周前才开始 React)。我正在寻找经过深思熟虑的策略,因此如果您能尽力提供完整和连贯的回复,我将不胜感激。我真的很感激。
App.js
class App extends Component
render()
return(
<Router>
<div>
<Navbar bg="light" variant="light">
<Navbar.Brand href="#home">My Application</Navbar.Brand>
<Nav className="mr-auto">
<Link to="/signup" className="nav-link">Signup</Link>
<Link to="/login" className="nav-link">Login</Link>
<Link to="/feed" className="nav-link">Search</Link>
<Link to="/create-post" className="nav-link">Create</Link>
</Nav>
<Form inline>
<Button variant="outline-primary">Logout</Button>
</Form>
</Navbar>
</div>
<Switch>
<Route path = '/signup' component = Signup />
<Route path = '/login' component = Login />
<Route path = '/feed' component = Feed />
<ProtectedRoute path = '/create-post' component = CreatePost />
</Switch>
</Router>
)
Login.js
class Login extends Component
constructor(props)
super(props)
this.state =
username: "",
password: ""
this.handleChange = this.handleChange.bind(this)
this.handleSubmitForm = this.handleSubmitForm.bind(this)
handleChange(event)
//console.log(event.target.name)
this.setState([event.target.name]: event.target.value)
handleSubmitForm()
const user =
username: this.state.username,
password: this.state.password
const url = 'http://localhost:9000/api/login'
fetch(url,
method: 'POST',
credentials: 'include',
headers:
'Content-Type': 'application/json'
,
body: JSON.stringify(user)
)
.then((response) => response.json())
.then((data) =>
if (data.status === 1)
this.props.history.push('/feed')
console.log(data)
)
.catch((error) =>
console.log('Error', error)
)
render()
return (
<div>
<Card className="card-login" style= width: '18rem' >
<Card.Body>
<Card.Title>Login</Card.Title>
<Form>
<Form.Group>
<Form.Control placeholder ="Username"
name = "username"
value = this.state.username
onChange = this.handleChange/>
</Form.Group>
<Form.Group>
<Form.Control type ="password"
placeholder="Password"
name = "password"
value = this.state.password
onChange = this.handleChange />
</Form.Group>
<Button variant ="primary"
value="Submit"
onClick=this.handleSubmitForm>Submit
</Button>
</Form>
</Card.Body>
</Card>
</div>)
Protectedroute.js
class ProtectedRoute extends Component
constructor(props)
super(props)
this.state =
isAuthenticated: false,
isLoading: true
this.isAuthenticated = this.isAuthenticated.bind(this)
componentDidMount()
this.isAuthenticated()
isAuthenticated()
const url = 'http://localhost:9000/api/auth'
fetch(url,
method: 'GET',
credentials: 'include',
headers:
'Content-Type' : 'application/json'
)
.then((response) => response.text())
.then((data) =>
if (data === 'true')
this.setState(
isAuthenticated: true,
isLoading: false
)
else
this.setState(
isAuthenticated: false,
isLoading: false
)
)
.catch((err) =>
console.log('Error', err)
)
render()
const Component = this.props.component
if (this.state.isLoading === true)
return (<div>Loading</div>)
return(
<Route render=(props) => this.state.isAuthenticated && !this.state.isLoading ? (<Component ...this.props/>) : (<Redirect to ='/login' />) />
)
api.js(快速后端)
router.post('/login', function(req,res,next)
const query1 = "SELECT * FROM users WHERE username = TRIM(?) AND pass = TRIM(?)"
database.query(query1, [req.body.username, req.body.password])
.then((result) =>
if (result.length)
if (req.session.username)
res.json('message': 'You are already logged in', 'status': 0)
else
req.session.username = req.body.username
res.json('message': 'You have successfully logged in', 'status': 1)
else
if (req.session.username)
res.json('message': 'You are already logged in', 'status': 0)
else
res.json('message': 'Incorrect Credentials', 'status': 0)
).catch((err) => res.send(err))
)
router.get('/auth', (req, res, next) =>
if (req.session.username)
res.send(true)
else
res.send(false)
)
【问题讨论】:
【参考方案1】:嗯,显然需要全局状态,您可以使用 React Context、Redux 甚至在App
组件中设置身份验证状态,传递改变状态的方法,即。 setAuth
,作为 Login
组件的道具。
class App extends Component
constructor(props)
super(props);
this.setAuth = this.setAuth.bind(this);
this.state =
isAuthenticated: false
;
setAuth(value)
this.setState(
isAuthenticated: value
);
<Route path='/login' component=() => <Login setAuth=this.setAuth /> />
我是否应该将身份验证逻辑从我的 Login.js 路由中移出? 进入我的主要 App.js 组件并传递状态?那岂不是 效率非常低,因为每次我渲染一个新视图时, App.js 正在使用我的后端 api 执行另一个提取以验证是否 用户有一个未过期的会话?
您是指Protectedroute
组件中发生的逻辑吗?正如你所说,我会将其提取到App
组件中,因为在一个场景中
<ProtectedRoute path = '/create-post' component = CreatePost />
<ProtectedRoute path = '/post-list' component = PostList />
<ProtectedRoute path = '/update-post' component = UpdatePost />
当您想访问'/update-post'
部分时,它会检查用户是否经过多次身份验证。
【讨论】:
感谢您的详尽回答。您给出的第一个响应是在子组件中修改 App 状态的一个很好的示例。但是,关于您的第二个回复,我想确保我对您的理解正确:您是否建议我摆脱ProtectedRoute
并将我所有的获取身份验证逻辑从 ProtectedRoute
移动到 App
?如果是这种情况,我的App
组件不会在每次安装新组件时执行获取吗? @Józef Podlecki
如果您将请求放入componentDidMount
然后更改状态,那么它仍然会再次执行获取。但是shouldComponentUpdate(nextProps)
来救援,在那里你可以创建一个非常简单的谓词,忽略isAuthenticated
属性更改或只返回false
很好。这是公认的答案。感谢您提供反馈。 @Józef Podlecki以上是关于如果用户登录或未登录,实现条件导航栏的策略的主要内容,如果未能解决你的问题,请参考以下文章