reactjs - 每当我重新加载仪表板时,我的登录组件都会闪烁
问题描述
我正在使用 reactjs 构建具有身份验证和授权的登录/注册系统。如果通过身份验证(jsonwebtoken),它应该将我路由到仪表板,否则将我重定向回登录。但是每当我重新加载它时,它都会在登录端点上停留一秒钟,然后返回仪表板。我怎样才能解决这个问题?
下面是一个显示我在说什么的 giphy
以下是与上述 App.js问题相关的组件
const App = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false)
// set isAuthenticated to true or false
const setAuth = (boolean) => {
setIsAuthenticated(boolean)
}
useEffect(() => {
// check if the person is still Authenticated
const isAuth = async () => {
try {
const res = await fetch('/auth/verify', {
method: 'GET',
headers: { token: localStorage.token},
})
const data = await res.json()
// if authenticated, then
if(data === true) {
await setIsAuthenticated(true)
} else {
await setIsAuthenticated(false)
}
} catch (err) {
console.error(err.message)
}
}
isAuth()
})
return (
<Fragment>
<Router>
<div className='container'>
<Switch>
<Route exact path='/login' render={props => !isAuthenticated ? <Login {...props} setAuth={setAuth} /> : <Redirect to='/dashboard' /> } />
<Route exact path='/register' render={props => !isAuthenticated ? <Register {...props} setAuth={setAuth} /> : <Redirect to='/login' />} />
<Route exact path='/dashboard' render={props => isAuthenticated ? <Dashboard {...props} setAuth={setAuth} /> : <Redirect to='/login' /> } />
</Switch>
</div>
</Router>
</Fragment>
);
登录组件
const Login = ({ setAuth }) => {
const [text, setText] = useState({
email: '',
password: ''
})
const { email, password } = text
const onChange = e => setText({ ...text, [e.target.name]: e.target.value})
const onSubmit = async (e) => {
e.preventDefault()
try {
// Get the body data
const body = { email, password }
const res = await fetch('/auth/login', {
method: 'POST',
headers: {"Content-Type": "application/json"},
body: JSON.stringify(body)
})
const data = await res.json()
if(data.token) {
// save token to local storage
localStorage.setItem("token", data.token)
setAuth(true)
toast.success('Login Successful')
} else {
setAuth(false)
toast.error(data)
}
} catch (err) {
console.error(err.message)
}
}
return (
<Fragment>
<h1 className='text-center my-5'>Login</h1>
<form onSubmit={onSubmit}>
仪表板组件
const Dashboard = ({ setAuth }) => {
const [name, setName] = useState('')
useEffect(() => {
const getName = async () => {
try {
const res = await fetch('/dashboard', {
method: 'GET',
// Get the token in localStorage into the header
headers: { token: localStorage.token }
})
const data = await res.json()
setName(data.user_name)
} catch (err) {
console.error(err.message)
}
}
getName()
// eslint-disable-next-line
}, [])
// Log out
const logOut = (e) => {
e.preventDefault()
localStorage.removeItem("token")
setAuth(false)
toast.success('Logged Out')
}
return (
<Fragment>
<h1 className='mt-5'>Dashboard</h1>
<p>Hello, {name}</p>
<button className='btn btn-primary my-3' onClick={e => logOut(e)}>Log Out</button>
</Fragment>
解决方案
我在上面的代码中发现了两个问题。
首先是您的 ueEffect 没有指定任何依赖项。当没有以这种方式指定依赖项时,useEffect 将在任何状态更改时运行。
useEffect(()=> {
// code here
}); // this one would run anytime any state changes in the component. You usually don't want this.
当指定依赖数组时,useEffect 中的代码将在任何依赖状态发生变化时运行。
useEffect(()=> {
// code here
},
[state1, state2, ...others...] //code would run when any of the state in this array changes
但是,在您的情况下,您可能希望运行该 useEffect 一次。为此,我们添加一个空数组作为依赖值。
useEffect(()=> {
// code here
},
[] //empty deps means that the code runs only once. When the component mounts
)
额外的想法
我还建议您向组件添加加载状态,以便在进行 API 调用时显示加载器。
您可能希望在进行 API 调用时显示加载程序(或者甚至默认将此状态设置为 true,因为 API 调用是您在应用程序中执行的第一件事)。
另外,考虑将 useEffect 放在自定义 Hook 中
推荐阅读
- c# - 后端 REST-API 中的 VIEW 是什么?
- python - 如何用该字典的键替换列向量中等于我拥有的字典的值的元素
- android - 从手机连接到 Azure 虚拟机
- c# - WeakReference 返回错误的对象
- java - Alfresco 批量导入元数据失败
- opengl - 什么取代了 CUDA 中的纹理参考管理
- java - 在 web.xml 或 weblogic.xml 中引用 Weblogic 12.2.1.3.0 中的自定义身份验证提供程序
- java - @ManyToMany 的实体不使用 Spring-Boot 和 Spring-JPA 保存
- python - 对组中的条目进行排序并按字母顺序返回第一个
- php - PHP exec缺少最后一行