Home > Mobile >  React app with Firebase User wont stay signed out / displaying user info wrong
React app with Firebase User wont stay signed out / displaying user info wrong

Time:11-23

Console.logs of currentUserenter image description here

I have a UserContext.js file which holds all of the useContext hooks. a Nav.js that displays some user info and a "Sign in" OR "Sign out" button. a Profile.js that displays user info. App.js that holds components and useContext.

Whats happening is if i sign in with a user everything gets displayed and i can navigate to various pages and the user information stays displayed. If i click Sign Out from the nav menu all of the user information instead of displaying “No User Info” shows empty fields on all the pages. And the “Sign Out” button appears again. I think this is happening because the UserContextProvider thats wrapping all of my components in App.js are calling auth.signout from the toggleUser function every time i navigate to a different page ? could i extract the toggleUser function out of the scope of UserContextProvider ? Or is something else happening?

App.js

import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';

import React from "react";
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { UserContextProvider } from '../../../src/util/Context/UserContext'

import Navmenu from '../Nav/Nav';
import Home from '../../Pages/Home/Home';
import Signin from '../../Pages/Sign-in/Sign-in';
import Signup from '../../Pages/Sign-up/Sign-up';
import Profile from '../../Pages/Profile/Profile';
import Footer from '../Footer/Footer';

const App = () => {
  return (
    <div className="App">
      <BrowserRouter>
        <UserContextProvider>
          <Navmenu />
          <hr className="p-0 m-0"></hr>
          <Routes>
            <Route exact path='/' element={<Home />} />
            <Route path='/signin' element={<Signin />} />
            <Route path='/signup' element={<Signup />} />
            <Route path='/profile' element={<Profile />} />
          </Routes>
          <Footer />
        </UserContextProvider>
      </BrowserRouter>
    </div>
  )
};

export default App;

UserContext.js

import React, { useContext, useState, useEffect } from 'react';
import { auth, createUserProfileDocument } from "../firebase/firebase.utils";

const UserContext = React.createContext(null);
const UserUpdateContext = React.createContext();

export const useUserContext = () => {
    // useContext hook 
    return useContext(UserContext);
}

export const useUserContextUpdate = () => {
    // useContext hook 
    return useContext(UserUpdateContext)
}

export const UserContextProvider = ({ children }) => {
    const [currentUser, setUser] = useState(null);
    let unsubscribeFromAuth = null;

    useEffect(() => {
        unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
            if (userAuth) {
                const userRef = await createUserProfileDocument(userAuth);

                userRef.onSnapshot(snapShot => {
                    setUser({
                        id: snapShot.id,
                        ...snapShot.data()
                    });
                });
            } else {
                setUser({ currentUser: userAuth })
            }
        });

        return () => {
            unsubscribeFromAuth();
        };
    }, [])
    

    const toggleUser = () => {
        auth.signOut()
        .then((currentUser) => {
            setUser(null)
        })
        .catch(e => console.log('There was a error:'(e)))
    }

    return (
        <UserContext.Provider value={currentUser} >
            <UserUpdateContext.Provider value={toggleUser} >
                {children}
            </UserUpdateContext.Provider >
        </UserContext.Provider >
    )
};

Nav.js

import React from 'react';
import { Link } from 'react-router-dom';
import './Nav.css';

import { useUserContext, useUserContextUpdate } from '../../../src/util/Context/UserContext';
import { auth } from '../../util/firebase/firebase.utils';

import { Nav, Navbar, NavDropdown } from 'react-bootstrap';
import Bell from './img/Bell.svg';
import Message from './img/Message.svg';
import Userprofile from './img/Userprofile.svg';
import Aboutme from './img/Aboutme.svg';
import Findfriends from './img/Findfriends.svg';
import Accountsetting from './img/Accountsetting.svg';

const Navmenu = ({  }) => {
    const currentUser = useUserContext();
    const toggleUser = useUserContextUpdate();

    return (
        <div className='tc f3'>
            <Navbar bg='light' expand='lg'>
                <a className="text-decoration-none" href="/">
                    <Navbar.Brand className="mx-2 mx-lg-5">Yelp-Clone</Navbar.Brand>
                </a>
                <Navbar.Toggle aria-controls="basic-navbar-nav" />
                <Navbar.Collapse id="basic-navbar-nav">
                    <hr></hr>
                    <Nav className='ml-5'>
                        <Nav.Link className='link-font' href="#home">Write a Review</Nav.Link>
                        <Nav.Link className='link-font' href="#link">Events</Nav.Link>
                        <Nav.Link className='link-font' href="#link">Talk</Nav.Link>
                    </Nav>
                    <div className="d-flex flex-row justify-content-lg-center align-items-center ml-auto">
                        <img className='nav-img me-2' src={Message}></img>
                        <img className='nav-img me-2' src={Bell}></img>
                        <img className='nav-img-lrg' src={Userprofile}></img>
                        <NavDropdown className='custom-dropdown-class me-3' id="basic-nav-dropdown">
                            <div className="d-flex flex-row">
                                <img className='nav-img-sml me-2' src={Userprofile}></img>
                                <div className="d-flex flex-column">
                                    {
                                        currentUser ?
                                            <span>{currentUser.displayName}</span>
                                            :
                                            <span>No User Found</span>
                                    }
                                    {
                                        currentUser ?
                                            <span>{currentUser.email}</span>
                                            :
                                            <span>No Email Found</span>
                                    }
                                </div>
                            </div>
                            <NavDropdown.Divider />
                            <div className="link-wrapper my-1">
                                <img className="link-font-sml me-2 inline-block" src={Aboutme}></img><a className="link-font-sml"><Link className="link-font-sml" to="/profile">About Me</Link></a>
                            </div>
                            <div className="link-wrapper my-1">
                                <img className="link-font-sml me-2 inline-block" src={Findfriends}></img><span className="link-font-sml">Find Friends</span>
                            </div>
                            <div className="link-wrapper my-1">
                                <img className="link-font-sml me-2 inline-block" src={Accountsetting}></img><span className="link-font-sml">Account Settings</span>
                            </div>
                            <NavDropdown.Divider />
                            <NavDropdown.Item className="p-0">
                                <div className="text-center options">
                                    {
                                        currentUser ?
                                            <a className="option" onClick={toggleUser}>
                                                Sign Out
                                            </a>
                                            :
                                            <a><Link className="option" to="/signin">Sign In</Link></a>
                                    }
                                </div>
                            </NavDropdown.Item>
                        </NavDropdown>
                    </div>
                </Navbar.Collapse>
            </Navbar>
        </div>
    )
}

export default Navmenu

CodePudding user response:

If I had to venture a guess as to why users don't stay "logged out" it is because of the inner subscription in the useEffect not being unsubscribed to as well. It can still update the user state.

Ensure you also reset the currentUser state to null when there'e a falsey userAuth value in the onAuthStateChanged callback.

useEffect(() => {
  let unsubscribeFromAuth = null;
  let unsubscribeFromSnapshot = null;

  unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
    if (userAuth) {
      const userRef = await createUserProfileDocument(userAuth);

      unsubscribeFromSnapshot = userRef.onSnapshot(snapShot => {
        setUser({
          id: snapShot.id,
          ...snapShot.data()
        });
      });
    } else {
      setUser(null); // <-- reset user state
    }
  });

  return () => {
    unsubscribeFromAuth();
    unsubscribeFromSnapshot();
  };
}, []);
  • Related