应用刷新时onAuthStateChanged Firebase侦听器会导致私有路由问题

时间:2020-11-05 16:49:54

标签: javascript reactjs firebase firebase-authentication

我目前已经用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时,该用户将被踢出本地路由并重定向到登录页面。我想知道是否有人对如何防止这种情况有任何建议。

1 个答案:

答案 0 :(得分:1)

您使用空值初始化currentUser状态变量:

const [currentUser, setCurrentUser] = useState(null)

这意味着currentUser最初在页面首次加载时始终为null。 Firebase SDK异步加载之前,直到一段时间后,才能确定先前的用户对象。您的代码需要为此做好准备。如果要求用户在呈现组件之前登录,则应等待onAuthStateChanged第一次使用实际用户对象进行触发。

您可以在this blog中了解有关Firebase Auth SDK行为的更多信息。