javascript - 使用带有 React 的 Context API 的 react-router-dom 的意外输出
问题描述
对于我的一个小项目,我正在尝试使用没有 Redux 的 React 上下文 API 来实现最基本的身份验证。
import { createContext, useContext, useState } from 'react'
export const AuthContext = createContext()
export const useAuth = () => {
const context = useContext(AuthContext)
if(context === null) throw new Error('Nope')
return context
}
export const AuthProvider = (props) => {
const [authenticated, setAuthenticated] = useState(false)
const login = () => {
setAuthenticated(true)
localStorage.setItem(storageKey, true)
}
const logout = () => {
setAuthenticated(false)
localStorage.setItem(storageKey, false)
}
return <AuthContext.Provider value={{authenticated, login, logout}} {...props}/>
}
export default AuthContext
我创建了一个上下文,并<App />
像这样将我的组件包装在其中;<AuthProvider></App></AuthProvider>
. 因为我想保持经过身份验证的状态,所以我使用浏览器的本地存储来存储一个简单的布尔值。
import PrivateRoute from './PrivateRoute'
import { useAuth } from './context/AuthContext'
import { AuthPage } from './pages'
import {
BrowserRouter,
Switch,
Route,
} from 'react-router-dom'
import { useEffect } from 'react'
const App = () => {
const { login, authenticated } = useAuth()
useEffect(() => {
const token = localStorage.getItem('user')
if(token && token !== false) { login() }
})
return (
<BrowserRouter>
<Switch>
<PrivateRoute exact path="/auth" component={AuthPage} />
<Route exact path='/'>
Dashboard
</Route>
</Switch>
</BrowserRouter>
)
}
export default App
然后,在我的<App />
组件中,我尝试调用login
从 给出的回调,AuthProvider
这让我假设这让我在页面刷新期间登录。当我尝试访问authenticated
当前组件中的变量时,它确实有效。它表明我已通过身份验证。
但是,当我尝试设置 PrivateRoute 时,只有经过身份验证的用户才能这样做:
import {
Route,
Redirect
} from 'react-router-dom'
import { useAuth } from './context/AuthContext'
const PrivateRoute = ({ component: Component, ...rest }) => {
const { authenticated } = useAuth()
if(authenticated) {
return <Route {...rest} render={(props) => <Component {...props} />} />
}
return <Redirect to={{ pathname: '/login' }} />
}
export default PrivateRoute
这没用。它只是将我重定向到登录页面。这是怎么来的?PrivateRoute
组件正在从组件中呈现<App />
。另外,这个问题的解决方案是什么?
解决方案
与其在每次重新渲染时都运行一个useEffect
来检查用户是否应该登录,不如authenticated
使用 localStorage 中的值来初始化你的状态:
const storageKey = 'user'
const initialState = JSON.parse(localStorage.getItem(storageKey)) ?? false
export const AuthProvider = (props) => {
const [authenticated, setAuthenticated] = useState(initialState)
const login = () => {
setAuthenticated(true)
localStorage.setItem(storageKey, true)
}
const logout = () => {
setAuthenticated(false)
localStorage.setItem(storageKey, false)
}
return <AuthContext.Provider value={{authenticated, login, logout}} {...props}/>
}
推荐阅读
- javascript - 切换到新笔记本电脑,突然我的 Vue 项目无法编译并出现 ES6 语法错误
- mysql - 如何在 Spotfire 中计算 NewTime
- blockchain - 获取从特定 eth 地址部署的所有合约
- chatbot - DialogFlow 中的动作和参数示例是什么?
- django - 如何在 django 中使用 request.POST[] 请求对象数组
- mysql - MySQL使用LIMIT
- intellij-idea - Intellij IDEA 插件,用于在控制台的 IDE 编辑器中读取和打印内容
- javascript - 更改 php 文件时,语义 UI 自动建议搜索栏不会在 Firefox 中加载结果(返回相同的语法)
- c++ - 使用引用的 constexpr 静态成员作为模板参数
- angular - PrimeNG 表获取过滤行