I am trying to use useContext to get the current logged in user details. I am getting an error in my console which says:
Uncaught TypeError: user is null
children Animate.jsx:79
Animate Animate.jsx:76
I am getting this error whenever I Logout. I am facing no errors in the console when I am logged in. Here is the code:
Context.js File:
import { onAuthStateChanged } from "firebase/auth";
import { useEffect, useState } from "react";
import { createContext } from "react";
import { auth } from "./firebase";
export const Context = createContext()
const ContextProviderfunc=({children})=>{
const use={
"mail":'history'
}
const [user,setuser]=useState({});
useEffect(()=>{
const unsubscribe = onAuthStateChanged(auth,(currentUser)=>{
// console.log(currentUser);
setuser(currentUser);
})
return ()=>{
unsubscribe();
}
},[])
return(
<Context.Provider value={user}>
{children}
</Context.Provider>
)
}
export default ContextProviderfunc
Animate.jsx File:
import React from 'react'
import {
BrowserRouter as Router, Routes, Route, useLocation, Link
} from 'react-router-dom'
import Navbar from './Navbar'
import RecipeCard from './RecipeCard'
import Details from './Details'
import { AnimatePresence, motion } from "framer-motion"
import Add from './Add'
import clicked from './RecipeCard'
import { useState } from 'react'
import Login from './Login'
import Register from './Register'
import Protected from './Protected'
import Logout from './Logout'
import Myrecipe from './Myrecipe'
import { useContext } from 'react'
import { Context } from '../Context'
export default function Animate(props) {
const user=useContext(Context)
const [pname, setpname] = useState()
function assign(nigga) {
setpname(nigga);
console.log(nigga);
}
const location = useLocation()
return (
<motion.div className='all'
>
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path='/Login' element={<Login />} />
<Route path='/Register' element={<Register />} />
<Route path='*' element={[<Protected><Navbar /></Protected>, <h2>Recipes</h2>,
<div className='recipes'>
{props.query ? props.query.map((object, i) => (
<Link className='lin' to='/Details'>
<div onClick={() => assign(object.Name)}>
<Protected><RecipeCard
src={object.src}
name={object.Name}
ingredients={object.Ingredients}
steps={object.Steps}
key={i}
/></Protected>
</div></Link>
)) : "Loading"}
<Link className='lin' to='/Add'>
<div className='cardcont'>
<img src='https://cdn.pixabay.com/photo/2017/11/10/05/24/add-2935429_960_720.png' alt="1" className='cardimg' />
<div className='cardbody'>
<h3>Add</h3>
</div>
</div></Link>
</div>
]} />
<Route path='/MyRecipe' element={[<Protected><Navbar /></Protected>, <h2>My Recipes</h2>,
<Protected>
<div className='recipes'>
{props.query2 ? props.query2.map((object, i) => {
if(user.email==object.email){
console.log(user.email);
return(<Link className='lin' to='/Details'>
<div onClick={() => assign(object.Name)}>
<Protected><RecipeCard
src={object.src}
name={object.Name}
ingredients={object.Ingredients}
steps={object.Steps}
key={i}
/></Protected>
</div></Link>)
}
}
) : "Loading"}
<Link className='lin' to='/Add'>
<div className='cardcont'>
<img src='https://cdn.pixabay.com/photo/2017/11/10/05/24/add-2935429_960_720.png' alt="1" className='cardimg' />
<div className='cardbody'>
<h3>Add</h3>
</div>
</div></Link>
</div>
</Protected>
]} />
<Route path='/Details' element={
[<Navbar />, props.query ? props.query.map((object, m) => {
if (pname == object.Name) {
console.log(object.Name);
return (<Details
src={object.src}
name={object.Name}
Ingredients={object.Ingredients}
Steps={object.Steps}
key={m}
/>)
}
}) : "Loading"]} />
<Route path='/Add' element={[<Navbar />, <Add />]} />
</Routes>
</AnimatePresence>
</motion.div>
)
}
line 79 of Animate.jsx
if(user.email==object.email){
console.log(user.email);
App.js file:
import Navbar from './components/Navbar';
import RecipeCard from './components/RecipeCard';
import { useContext, useEffect, useState } from 'react';
import { auth, db, storage } from './firebase'
import { collection, addDoc, getDocs, doc } from "firebase/firestore";
import { async } from '@firebase/util';
import Details from './components/Details'
import Animate from './components/Animate';
import {BrowserRouter as Router, Route,Routes} from 'react-router-dom'
import Add from './components/Add';
import ContextProviderfunc from './Context';
import { Context } from './Context';
function App() {
const [query, setquery] = useState()
const [query2, setquery2] = useState()
const [recipe, setrecipe] = useState()
const add = async (e) => {
e.preventDefault()
try {
const docRef= await addDoc(collection(db, "recipe"),
{
src: 'https://images.immediate.co.uk/production/volatile/sites/30/2017/02/Two-panna-cotta-on-plates-298e616.jpg',
ingredients: ['Dish'],
steps: ['Description']
}, {
src: 'https://imagesvc.meredithcorp.io/v3/mm/image?url=https://static.onecms.io/wp-content/uploads/sites/43/2022/04/19/22749-the-best-banana-pudding-mfs-366-1x1-1.jpg',
ingredients: ['Dish'],
steps: ['Description']
});
// console.log('morein');
// console.log("Document written with ID: ", docRef.id);
} catch (error) {
console.log('morein');
console.error("Error adding document: ", error);
}
}
useEffect(() => {
const getrecipe = async () => {
const data = await getDocs(collection(db, 'recipe'))
const data2 = await getDocs(collection(db, 'userrecipe'))
console.log(data);
setquery(data.docs.map((doc) => (
{
...doc.data(), id: doc.id
})
))
setquery2(data2.docs.map((doc) => (
{
...doc.data(), id: doc.id
})
))
console.log(query);
};
getrecipe();
}, []);
useEffect(() => {
// searchRecipes();
}, [])
return (
<div>
<ContextProviderfunc>
<Router>
<Animate query={query} query2={query2}/>
</Router>
</ContextProviderfunc>
</div>
);
}
export default App;
These two files I think are needed to debug. If any more code is needed I will provide it. Please find out the issue in the above code
CodePudding user response:
Whenever the user logs out, value of currentUser
will become null in here:
onAuthStateChanged(auth,(currentUser)=>{
// console.log(currentUser);
setuser(currentUser); // currentUser is null
})
Since you are updating the state (setuser
), The Context Provider rerenders and passes down null
as value
.
return(
<Context.Provider value={user}> // user is null, and is being passed down
{children}
</Context.Provider>
)
Within Animate
you receive the null
value.
const user=useContext(Context) // user is null, after loging out.
Long story short, user
is at times null
within Animate
, so you don't have the guarantee to use properties like email
, like this line below:
if(user.email==object.email){
console.log(user.email);
The solution: Wherever you need to use user
, first check if it equals to null.
CodePudding user response:
If you set logged out user ti be null
, you should not expect to retrieve email
address of null
.
You should check (read from context) if user still logged in.
For example :
if(user) {
return <div>I am logged in user and my email is {user.email} </div>
}
return <div>You are not logged In </div>
Specific to your case: check first user and then user.email to avoid Uncaught TypeError: user is null
if(user && user.email === object.email) .....
This is just a friendly suggestion, which is not related with your question: Use ===
instead of ==
for for information you can read this page