skip to Main Content

I’m trying to create a simple registration and login system with firebase auth, but whenever I restart the site in console.log it appears that the user is saved, but the application returns him to the login page, as if he was not saved in the system.

App.jsx:

import { useState, useEffect } from 'react'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { onAuthStateChanged } from 'firebase/auth'
import { auth } from './firebase'

// Pages
import SignUp from './pages/SignUp.jsx'
import SignIn from './pages/SignIn.jsx'
import Home from './pages/Home.jsx'

function App() {
  const [authUser, setAuthUser] = useState(null)

  useEffect(() => {
    const listen = onAuthStateChanged(auth, (user) => {
      if (user) {
        setAuthUser(user)
        console.log(user)
      } else {
        setAuthUser(null)
      }
    })
    return () => {
      listen()
    }
  }, [])

  return (
    <div>
      <BrowserRouter>
        <Routes>
          <Route path='/' element={authUser ? <Home/> : <Navigate to='signIn'/>}/>
          <Route path='/signup' element={<SignUp />} />
          <Route path='/signin' element={<SignIn />} />
        </Routes>
      </BrowserRouter>
    </div>
  )
}

export default App

SignIn.jsx:

import { signInWithEmailAndPassword } from 'firebase/auth'
import React from 'react'
import { Link, useNavigate } from "react-router-dom"
import { useState } from 'react'
import { auth } from "../firebase.js"

const SignIn = () => {
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")
    const nav = useNavigate()

    const handleSubmit = async (e) => {
        e.preventDefault()
        try {
            const userCredential = await signInWithEmailAndPassword(auth, email, password)
            console.log(userCredential)
            nav('/')
        } catch (error) {
            console.log(error)
        }
    }

    return (
        <div className='min-h-[100vh] flex flex-col justify-center'>
            <form className='w-[80vw] flex flex-col items-center mx-auto p-5 bg-neutral-content rounded-md' onSubmit={handleSubmit}>
                <h1 className='text-2xl font-bold mb-4'>Sign-In</h1>
                <label className="input input-bordered rounded flex items-center gap-2 my-3" htmlFor='email'>
                    <input name="email" type="email" className="grow" placeholder="Digit your email" onChange={(e) => setEmail(e.target.value)} value={email} required />
                </label>
                <label className="input input-bordered rounded flex items-center gap-2 my-3">
                    <input type="text" className="grow" placeholder="Digit your password" onChange={(e) => setPassword(e.target.value)} required value={password} />
                </label>
                <Link to='/signUp' className='text-sm mb-2'>Não tenho conta. <span className='underline'>Cadastrar-se</span></Link>
                <input type="submit" value="Entrar" className='btn rounded mt-3' />
            </form>
        </div>
    )
}

export default SignIn

SignUp.jsx:

import { createUserWithEmailAndPassword } from 'firebase/auth'
import React from 'react'
import { Link, useNavigate } from "react-router-dom"
import { useState } from 'react'
import { auth } from '../firebase'

const SignUp = () => {
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")
    const [confirmKey, setConfirmKey] = useState("")
    const navigate = useNavigate()

    const handleSubmit = async(e) => {
        e.preventDefault()
        console.log(`email: ${email} | senha: ${password} | senha dnv: ${confirmKey}`)
        setEmail("")
        setPassword("")
        setConfirmKey("")
        try {
            const userCredentials = await createUserWithEmailAndPassword(auth, email, password)
            console.log(userCredentials)
            navigate('/')
        } catch (error) {   
            console.log(error)
        }
        
    }

    return (
        <div className='min-h-[100vh] flex flex-col justify-center'>
            <form className='w-[80vw] flex flex-col items-center mx-auto p-5 bg-neutral-content rounded-md' onSubmit={handleSubmit}>
                <h1 className='text-2xl font-bold mb-4'>Sign-up</h1>
                <label className="input input-bordered rounded flex items-center gap-2 my-3" htmlFor='email'>
                    <input name="email" type="email" className="grow" placeholder="Digit your email" onChange={(e) => setEmail(e.target.value)} value={email} required />
                </label>
                <label className="input input-bordered rounded flex items-center gap-2 my-3">
                    <input type="text" className="grow" placeholder="Digit your password" onChange={(e) => setPassword(e.target.value)} required value={password} />
                </label>
                <label className="input input-bordered rounded flex items-center gap-2 my-3">
                    <input type="text" className="grow" placeholder="Confirm your password" onChange={(e) => setConfirmKey(e.target.value)} required value={confirmKey} />
                </label>
                <Link to='/signin' className='text-sm mb-2'>Já tenho uma conta. <span className='underline'>Logar-se</span></Link>
                <input type="submit" value="Cadastrar" className='btn rounded mt-3' />
            </form>
        </div>
    )
}

export default SignUp

The home page is just a div written home, nothing much that disrupts the logic of the code.

2

Answers


  1. Try this

    return (  
        <div>  
          <BrowserRouter>  
            <Routes>  
              <Route path='/' element={authUser !== null ? <Home/> : <Navigate to='signIn'/>}/>  
              <Route path='/signup' element={<SignUp />} />  
              <Route path='/signin' element={<SignIn />} />  
            </Routes>  
          </BrowserRouter>  
        </div>  
      )  
    
    Login or Signup to reply.
  2. That is happening due to Redirect is executed before onAuthStateChanged is executed and the user is set. It just uses your initial user’s value which is null in a useState initialization code.

    You can add 1 extra useState flag-variable that will indicate if auth-check code is fired at least once, and then to reuse it with redirect logic:

    const [isAuthReady, setIsAuthReady] = useState(false);
    

    and

      useEffect(() => {
        const listen = onAuthStateChanged(auth, (user) => {
          if (user) {
            setAuthUser(user)
            console.log(user)
          } else {
            setAuthUser(null)
          }
          setIsAuthReady(true);
        })
        return () => {
          listen()
        }
      }, [])
    

    And just before the return section of your App component add another return with

    if (!isAuthReady) return <p>Loading...</p>
    

    Or anything else you prefer.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search