'User logged in/out status set as context, and creating problems when that context is used
In my component write-review.js, I need to extract the uid from the current logged-in user.
I have a function in FirebaseContext.js that creates an auth listener and sets the auth status to state, and then converts that state into context so I can use it across my entire app:
FirebaseContext.js
import { useState } from 'react'
import { auth } from "./firebaseConfig";
import { onAuthStateChanged } from 'firebase/auth';
import { createContext } from "react";
export const FirebaseContext = createContext()
const FirebaseContextProvider = (props) => {
const [activeUser, setActiveUser] = useState(null);
onAuthStateChanged(auth, (user) => {
if(user){
setActiveUser(user)
}else{
setActiveUser(null)
}
})
return (
<FirebaseContext.Provider value={{ activeUser }}>
{props.children}
</FirebaseContext.Provider>
);
};
export default FirebaseContextProvider
In my write-review.js file, I'm trying to pull the uid out of the auth listener context I created. However this is leading to some strange behaviour.
Sometimes I'm able to destruct the uid of the context, as follows:
const { activeUser } = useContext(FirebaseContext)
const {uid} = activeUser
console.log(uid) //yields the uid
However sometimes I get one of two errors:
1.
Uncaught TypeError: Cannot destructure property 'uid' of 'activeUser' as it is null.
Warning: React has detected a change in the order of Hooks called by WriteReview. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
I'm confused as to why this is happening, because in other components I'm using this context without problem.
Any ideas on how to extact the uid from a signed in user, using context in this way?
The project structure is roughly as follows:
src
|_components
| |_Header.js
|
|_pages
| |
| |_write-review.js
|
|_firebaseConfig.js
|
|_FirebaseContext.js
Here's the write-review.js component:
import { useParams,useNavigate } from 'react-router-dom';
import { getAuth } from 'firebase/auth'
import { useState,useContext, useEffect } from 'react'
import { FirebaseContext } from '../FirebaseContext';
import { useVenues } from '../useVenue'
import { GetUsers } from '../useUser';
import { firebase,FieldValue } from '../firebaseConfig'
import Header from '../components/Header'
const WriteReview = () => {
const navigate = useNavigate()
const { activeUser } = useContext(FirebaseContext)
// const { userData } = GetUsers()
const [ {
title,
review,
rating,
ratingService,
ratingFood,
ratingValue,
ratingAtmosphere
}, setReview ] = useState({
title:'',
review:'',
rating:'',
ratingService:'',
ratingFood:'',
ratingValue:'',
ratingAtmosphere:'',})
let {id} = useParams()
const { venueData } = useVenues()
const filteredVenue = venueData.filter(item => {
return item.id === id
})
const handleChange = (e) => {
const { name,value } = e.target
e.preventDefault()
setReview(prevState => ({
...prevState,
[name]:value
}))
}
const handleSubmit = async (e) => {
const newReview = {
title:title,
review:review,
rating:rating,
ratingService: ratingService,
ratingFood: ratingFood,
ratingValue:ratingValue,
ratingAtmosphere:ratingAtmosphere
}
e.preventDefault()
await firebase
.firestore()
.collection('venues')
.doc(id)
.update({
reviews: FieldValue.arrayUnion(newReview)
})
navigate(`/venue/${id}`)
}
return(
<div>
<Header/>
<div className='write-review-top'>
{filteredVenue.map(venue => {
return(
<div className='write-review-top-img'>
<img src = {venue.photoUrl}/>
<div className='write-review-top-text'>
<p>{venue.name}</p>
<p>Venue address</p>
</div>
</div>
)
})}
</div>
<div className='write-review-form'>
<form onSubmit = {handleSubmit}>
<h2>Your first hand experiences helps other travellers!</h2>
<label>
Your overall rating of this venue <br></br>
<select name = 'rating' onChange = {handleChange}>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
<option value = '4'>4</option>
<option value = '5'>5</option>
</select>
</label>
<label>Title of your review <br></br>
<input type = 'text' name = 'title' value = {title} onChange = {handleChange}/>
</label>
<label >Your review <br></br>
<textarea type = 'text' name = 'review' value = {review} onChange = {handleChange}/>
</label>
<label>
Service <br></br>
<select name = 'ratingService' onChange = {handleChange}>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
<option value = '4'>4</option>
<option value = '5'>5</option>
</select>
</label>
<label>
Food <br></br>
<select name = 'ratingFood' onChange = {handleChange}>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
<option value = '4'>4</option>
<option value = '5'>5</option>
</select>
</label>
<label>
Value <br></br>
<select name = 'ratingValue' onChange = {handleChange}>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
<option value = '4'>4</option>
<option value = '5'>5</option>
</select>
</label>
<label>
Atmosphere <br></br>
<select name = 'ratingAtmosphere' onChange = {handleChange}>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
<option value = '4'>4</option>
<option value = '5'>5</option>
</select>
</label>
<button type = 'submit'>Submit</button>
</form>
</div>
</div>
)
}
export default WriteReview
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
