我目前已经用firebase初始化了一个React App。在应用程序中,我使用react-router-dom创建了一个开放的登录路由和一个私有的Home路由。我的app.js看起来像这样:
App.js:
import React from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import Login from './pages/Login'
import Home from './pages/Home'
import PrivateRoute from './utils/PrivateRoute'
const App = () => {
return (
<BrowserRouter>
<Switch>
<PrivateRoute exact path='/' component={Home} />
<Route path='/login' component={Login} />
</Switch>
</BrowserRouter>
)
}
export default App
我正在使用onAuthStateChanged firebase事件侦听器将currentUser存储在上下文中,如下所示:
AppContext:
import { useEffect, useState, createContext } from 'react'
import { auth } from '../utils/firebase'
export const AppContext = createContext()
export const AppProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null)
useEffect(() => {
auth.onAuthStateChanged(setCurrentUser)
}, [])
return (
<AppContext.Provider value={{ currentUser }}>
{children}
</AppContext.Provider>
)
}
当用户通过登录路径登录时:
登录:
import React, { useState, useCallback, useContext } from 'react'
import { auth } from '../utils/firebase'
import { useHistory, Redirect } from 'react-router-dom'
function Login() {
const [formData, setFormData] = useState({ email: '', password: '' })
const history = useHistory()
const handleChange = ({ target: { name, value } }) => {
setFormData({ ...formData, [name]: value })
}
const handleSubmit = useCallback(
async event => {
event.preventDefault()
await auth
.createUserWithEmailAndPassword(formData.email, formData.password)
.then(user => {
console.log(user)
history.push('/')
})
.catch(err => {
alert(err)
})
},
[history, formData.email, formData.password]
)
return (
<div className='form-container sign-up-container'>
<form className='register-form' onSubmit={handleSubmit}>
<h1>Create Account</h1>
<div className='social-container'>
<div className='social'>
<i className='fab fa-facebook-f'></i>
</div>
<div className='social'>
<i className='fab fa-google-plus-g'></i>
</div>
<div className='social'>
<i className='fab fa-linkedin-in'></i>
</div>
</div>
<span>or use your email for registration</span>
<input
type='email'
placeholder='Email'
name='email'
onChange={handleChange}
/>
<input
type='password'
placeholder='Password'
name='password'
onChange={handleChange}
/>
<button type='submit'>Sign Up</button>
</form>
</div>
)
}
export default Login
currentUser已成功存储在上下文中,并且该用户被推入了专用Home路由。
私人路线如下:
import React, { useContext } from 'react'
import { Route, Redirect } from 'react-router-dom'
import { AppContext } from '../context/AppContext'
const PrivateRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useContext(AppContext)
return (
<Route
{...rest}
render={routeProps =>
!!currentUser ? (
<Component {...routeProps} />
) : (
<Redirect to={'/login'} />
)
}
/>
)
}
export default PrivateRoute
我遇到的问题是,当应用程序刷新时,currentUser最初将变为null,然后再加载currentUser的信息。当currentUser在刷新时为null时,该用户将被踢出本地路由并重定向到登录页面。我想知道是否有人对如何防止这种情况有任何建议。
答案 0 :(得分:1)
您使用空值初始化currentUser
状态变量:
const [currentUser, setCurrentUser] = useState(null)
这意味着currentUser
最初在页面首次加载时始终为null。 Firebase SDK异步加载之前,直到一段时间后,才能确定先前的用户对象。您的代码需要为此做好准备。如果要求用户在呈现组件之前登录,则应等待onAuthStateChanged
第一次使用实际用户对象进行触发。
您可以在this blog中了解有关Firebase Auth SDK行为的更多信息。