React Firebase UseEffect Firestore - reactjs

I've got a user bar component directly adjacent to my navbar, showing avatar and display name (user details saved within a userid-named doc). I followed the firestore documentation for real time updates. Placed inside a use effect hook, which has a dependency array, but is firing repetitively, firing off about 4,000 calls a minute per logged in user).
I really just want the snapshot to update when a user updates their display name or avatar. (found on a different form component)
I console logged every useEffect hook in my project to narrow it down to this component. Is there something about the dependency array causing this? Is there a better way to write this? Thanks!
export default function UserBar() {
const { user } = useAuthContext()
const [me, setMe] = useState([])
useEffect(() => {
//user real-time subscription for avatar and displayname
const auth = getAuth()
const fireUser = auth.currentUser
const unsub = onSnapshot(doc(db, "users", fireUser.uid), (doc) => {
if (doc.exists()) {
setMe(doc.data())
console.log('looking for duplicate - userbar unsub')
} else {
console.log("No such document!")
}
})
return () => unsub()
}, [me])
return (
<>
{user && (
<div className="user-bar">
<p className="oneHunid">Welcome
<span className="bold"> {user.displayName}!</span>
</p>
<Avatar src={me.photoURL} />
</div>
)}
</>
)
}

You do not want to have [me] as a dependency when inside the useEffect() you call setMe(). That leads to an infinite loop:
me gets a new value, so render
me has a new value, so run useEffect()
useEffect() calls setMe()
go to # 1
Based on the above, it looks like what you really want is to have your useEffect() be dependent on the value of auth.currentUser. So get that value outside of the useEffect() and then check to be sure it is not null. If it is not null, then start the onSnapshot() listener.
BTW: if it would be of help, check out the user profiles with Firebase Auth project I developed. In particular, check out the FirebaseProvider.js which is where I configure the Firebase project and get all of its services, and AuthProvider.js which provides login, logout, registration and "user profile".

Related

Do I need to store isUserSignIn for componet rendering in Local Storage(React,Next,Firebase Auth)

(Firebase Google Signin + React(Next) )
If user sign in , setState to true.
And render the home component and welcome(login) component in index.js by state value.I made an application by storing that state in local storage and I think it is not a good practice. So if I don't use local storage there is a issue when user signed in and it should reach the home component but , user can also see welcome component before home component.
Logic index.js -> if userSignin (Home) : (Login)
Conditional Rendering
{isSignin ? (<>Home Component</>) : (<Welcome Component/>)}
state
const [isSignin, setisSignin] = useState(false);
changing state if user signin
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setisSignin(true);
console.log(user);
}else {
setisSignin(false);
}
});
}, []);
firebase auto use localstorage when u signin an account. please check it in your browser localstorage. You don't need to store it by yourself. Then, when user revisit that website from the same web browser, firebase auto login (unless he did not logout). However, that auto login needs some amount of time. you need to do something during that amount of time. after that time, isSignIn will be true. I suggest something like this.
const [isSignIn, setSignIn] = useState(null);
useEffect(()=> listener_to_authstate_change() ,[])
if (isSignIn === null) return null; // something you like to show example - <Loading />
if (isSignIn === false) return <SignIn Component />
if (isSignIn === true) return <Home Component />

how can ı handle react with firebase authentication problem?

I am trying develop user authentication page in react with firebase.
I can sign in but then sign in doesn't change to sign out.
what is the problem?
const handleAuthentication = () => {
if(user){
auth.signOut();
}
}
<div onClick={handleAuthentication}
className="header_option">
<span
className="header_optionLineOne" >Hello, Guest</span>
<span
className="header_optionLineTwo" >{user ?
'Sign Out': 'Sign In'}</span>
</div>
Probably the user is actually signed out, but the UI is not rerendering as it doesn't know about the change.
To fix this, you'll want to store the user in the component's state, with either setState or a useState hook:
const [user, setUser] = useState(null);
auth.onAuthStateChanged((user) => {
setUser(user);
});
With the user being part of the state, the call to setUser(user) will cause the component to rerender and thus show the updated (lack of) user information.
Also see the first code snippet in the Firebase documentation on getting the current user.

My react component never displays the information from the database

I have a small web app displays game information.
I am using React hooks so that the component is modern.
When this component loads, I want it to connect to the api via axios, and get the description of the game.
But when it loads, the value inside the <GameVault /> is always null.
When I look in the database, it is not null. If I hit the api directly, it does return the game description.
My console.log is hit twice for some reason. The first time it's null, the second time it has the needed value.
I am also not getting any errors, so I don't know why this isn't working.
Here is the code:
const Vault = ({ game }) => {
const [gameText, setGameText] = useState(null);
async function fetchGameText() {
const response = await axios.get(`/api/gamermag/${game.id}/gameDescriptionText`);
setGameText(response.data);
}
useEffect(() => {
fetchGameText();
}, []);
console.log("gameText: ", gameText);
const gamerValue = useMemo(() => {
return gameText ? gameText : "";
}, [gameText]);
return (
<GameVault value={gamerValue} />
)
}
export default Vault;
Is there a way to get this to work?
Thanks!
You need to wait for the data to load from the server. While the data is being fetched, gameText will be null and when it's done fetching, it stores the response. That is why your console.log hit twice. The first time is the component's first render, and the second time is when the gameText changes its state which caused a rerender.
You need to add logic to wait for the data.
if(!gameText){
return <div>loading...</div>
}

How can I stay the user in the same page?

Every time I reload the my account page, it will go to the log in page for a while and will directed to the Logged in Homepage. How can I stay on the same even after refreshing the page?
I'm just practicing reactjs and I think this is the code that's causing this redirecting to log-in then to home
//if the currentUser is signed in in the application
export const getCurrentUser = () => {
return new Promise((resolve, reject) => {
const unsubscribe = auth.onAuthStateChanged(userAuth => {
unsubscribe();
resolve(userAuth); //this tell us if the user is signed in with the application or not
}, reject);
})
};
.....
import {useEffect} from 'react';
import { useSelector } from 'react-redux';
const mapState = ({ user }) => ({
currentUser: user.currentUser
});
//custom hook
const useAuth = props => {
//get that value, if the current user is null, meaning the user is not logged in
// if they want to access the page, they need to be redirected in a way to log in
const { currentUser } = useSelector(mapState);
useEffect(() => {
//checks if the current user is null
if(!currentUser){
//redirect the user to the log in page
//we have access to history because of withRoute in withAuth.js
props.history.push('/login');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[currentUser]); //whenever currentUser changes, it will run this code
return currentUser;
};
export default useAuth;
You can make use of local storage as previously mentioned in the comments:
When user logs in
localStorage.setItem('currentUserLogged', true);
And before if(!currentUser)
var currentUser = localStorage.getItem('currentUserLogged');
Please have a look into the following example
Otherwise I recommend you to take a look into Redux Subscribers where you can persist states like so:
store.subscribe(() => {
// store state
})
There are two ways through which you can authenticate your application by using local storage.
The first one is :
set a token value in local storage at the time of logging into your application
localStorage.setItem("auth_token", "any random generated token or any value");
you can use the componentDidMount() method. This method runs on the mounting of any component. you can check here if the value stored in local storage is present or not if it is present it means the user is logged in and can access your page and if not you can redirect the user to the login page.
componentDidMount = () => { if(!localStorage.getItem("auth_token")){ // redirect to login page } }
The second option to authenticate your application by making guards. You can create auth-guards and integrate those guards on your routes. Those guards will check the requirement before rendering each route. It will make your code clean and you do not need to put auth check on every component like the first option.
There are many other ways too for eg. if you are using redux you can use Persist storage or redux store for storing the value but more secure and easy to use.

Managing exit of a user from a game 'room' on React?

This might seem complicated - I am working on a game app on React that involves users all joining a certain <Route> in my project. When all users are on this route, the game is unpaused and if not the game is paused.
My question is: How can I manage to suddenly pause the game if a user leaves the link or closes the tab ? Is there any way to actively check this on react? I figured useEffect hook might be useful but I don't know how to get the number of users leaving a site or closing the tab in real-time at once.
Here is some basic code to understand what I want. I have a functional React component <GameSession> that hosts a game when users join this link:
const GameSession = ({userRegistered}) =>{
const [paused, setPaused] = useState(false);
useEffect(() => {
// store some user related data in localStorage when the user loads
}, []);
useEffect(() => {
setPaused(numberofUsersInGame === totalUsers ? false : true)
}, [numberofUsersInGame]);
/* MY PROBLEM IS IN THIS EFFECT HOOK ABOVE. HOW TO CHECK IF A USER HAS LEFT THIS
COMPONENT OR PAGE SO I CAN UPDATE numberofUsersInGame ? */
if(!userRegistered)
return <Redirect to="/dashboardpage">
if(paused)
return <PausedComponent /> /*this component should fire a return when total
number of users registered to this game is not
equal to current number of users who are
active on the GameSession component (this link)*/
return (
<Fragment>
<GameComponent>
</Fragment>
);
};
GameSession.propTypes = {
// PropTypes go here
};
const mapStateToProps = (state) => ({
//states go here
});
export default connect(mapStateToProps, mapDispatchToProps)(GameSession);

Resources