I have a React/Firebase app where I'm extracting the current active user from firebase, and passing it to the rest of the app as context.
The user is set to context in the FirebaseContext.js
file, and the problem is this: after I log in and console log the user object, it is logged as null
. However, when I make a change in the FirebaseContext.js
file and save it, the user object returns the correct object.
It's as if the code in FirebaseContext.js
is not executed on login, and I'm not sure why. My understanding is that once a user logs in, their log in status is available to the entire app - or perhaps I've misunderstood. Suggestions on how to get login to work?
The structure of the project is roughly as follows:
src
|_components
| |_Header.js
|
|_pages
| |
| |_login.js
|
|_firebaseConfig.js
|
|_FirebaseContext.js
FirebaseContext.js
import { useEffect,useState } from 'react'
import { auth } from "./firebaseConfig";
import { createContext } from "react";
export const FirebaseContext = createContext()
const user = auth.currentUser
console.log(`context user: ${user}`)
const FirebaseContextProvider = (props) => {
return(
<FirebaseContext.Provider value = {{user}}>
{props.children}
</FirebaseContext.Provider>
)
}
export default FirebaseContextProvider
Here's the login component Login.js
import { useState,useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth'
const Login = () => {
const auth = getAuth()
const user = auth.currentUser
console.log(`this is user login ${user}`)
const [{ email, password },setFormDetails] = useState({ email:'', password:''})
const navigate = useNavigate()
const handleChange = (e) => {
e.preventDefault()
const { name, value } = e.target
setFormDetails(prevForm => ({
...prevForm,
[name]: value
}))
}
const handleSubmit = (e) => {
e.preventDefault()
const auth = getAuth()
signInWithEmailAndPassword(auth,email,password)
.then(() => {
console.log('logged in')
navigate('/')
})
.catch(err => {
console.log(err)
})
}
useEffect(() => {
document.title = 'Login - Wellyadvisor'
},[])
return(
<div className = 'signup-container'>
<p>Wellyadvisor</p>
<form onSubmit = {handleSubmit} method = 'POST'>
<input
type = 'text'
placeholder = 'Email'
aria-label = 'Enter your email'
name = 'email'
onChange = {handleChange}
/>
<input
type = 'password'
placeholder = 'Password'
aria-label = 'Enter your password'
name = 'password'
onChange = {handleChange}
/>
<button type ='submit'>
Login
</button>
</form>
</div>
)
}
export default Login
CodePudding user response:
When you run:
const user = auth.currentUser
That is a synchronous calls that simply returns the value of the property when that line of code executes.
But the user's authentication state is an interactive process with many moving parts, such as your call to signInWithEmailAndPassword
, but also the SDK itself, which automatically refreshes the sign-in state every hour, and signs the user out when for example you've disabled their account.
For this reason you should use an auth state listener, as shown in the first code sample in the documentation on getting the current user:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
If you use this approach, and store the user in the state, you can simply refresh the state when the login state changes, which will then reactively update the UI.