I am trying to create a project in that login functionality is good and working properly but when I logged in and refreshed the screen the logout button disappears and the login link will come and then again logout button will come.to understand perfectly watch the video https://drive.google.com/file/d/1UvTPXPvHf4EhcrifxDEfPuPN0ojUV_mN/view?usp=sharing, this is because of
const AuthContext = React.createContext()
//useauth will return the AuthContext
export const useAuth = () => {
return useContext(AuthContext)
}
export const Authprovider = ({ children }) => {
var name
auth.onAuthStateChanged((user) => {
name = user
})
const [currentuser, setcurrentuser] = useState(name)
const [load, setload] = useState(true)
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setcurrentuser(user)
setload(false)
})
return unsubscribe
}, [])
const value = {
currentuser,
signup,
login,
load,
}
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
I wrapped the AuthProvider component around the app component so that I can use the values like current user .
in Header component where login link, logout button is there
const { currentuser, load } = useAuth()
const logout = () => {
try {
auth.signOut().then(() => {
console.log('logged out')
})
} catch {
alert('logout is not possible')
}
}
//some code
{currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
if there is a current user then the logout button will appear otherwise login link will appear but when refreshing there is some problem I tried many ways now I am out of ideas. "Even I refresh the page when logged in the logout button should not disappear" can you tell me how to do this?
to understan watch the video in the link
That's because you're not using load state try this:
//some code
{ load ? <div>loading</div>
: currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
Related
In my provider, I called my get-registered-user API like this:
const AuthProvider = ({ children, isAuth }) => {
const [userIsLoggedIn, setUserIsLoggedIn] = useState(false);
useEffect(() => {
axiosInstance.get('/api/users/registered-user').then(res => {
if (Object.values(res.data.user).length > 0) {
setUserIsLoggedIn(true);
}
});
}, []);
const login = () => {
setUserIsLoggedIn(true);
};
const logout = () => {
setUserIsLoggedIn(false);
};
const contextValue = {
login,
logout,
userIsLoggedIn
};
return (
<AuthContext.Provider value={contextValue}>
{ children }
</AuthContext.Provider>
)
}
export default AuthProvider;
This works but calling an API inside useEffect works after the DOM renders. I would like to do that before the DOM renders. I found getServerSideProps doesn't work inside Context Provider. I need your suggestion on this.
I can't seem to figure out how to maintain the login state.
I login, the app shows the condition if logged in, but then if I refresh the page, it asks me to login again.
I am using onAuthStateChanged, I just dont know what else to do.
This shows up when user not logged in
after I click login, this shows up
but when i click refresh, it shows you must login again.
here is my firebase config (the relevant bits)
function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsubsubscribe = onAuthStateChanged(auth, (user) =>
setCurrentUser(user)
);
return unsubsubscribe;
}, []);
return currentUser;
}
export { app, storage, auth, database, useAuth };
I decide to create a function useAuth() inside firebase.config so i dont have to recreate it everywhere i need it.
Here is the login code
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const currentUser = useAuth();
const [loading, setLoading] = useState(false);
function login(email, password) {
return auth
.setPersistence(browserLocalPersistence)
.then(() => {
signInWithEmailAndPassword(auth, email, password).catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
}
}
And here is the page I want to show if the user is logged in. It shows to correct component if logged in , but when i refresh the page it doesnt remember the logged in user.
here is the code for the page
const Properties = () => {
const currentUser = useAuth();
onAuthStateChanged(auth,(user))
return (
<>
<Head>
<title>Add Property</title>
<meta name="keywords" content="web dev" />
</Head>
<h1>Add Property</h1>
<p>Welcome to the add Property new</p>
{console.log("user logged in? " + currentUser?.email)}
{currentUser ? (
<AddProperty />
) : (
<div>
<p style={{ color: "red" }}>You must be loggedin to add a property</p>{" "}
<Login />
</div>
)}
</>
);
};
export default Properties;
This question already has an answer here:
How to use firebase authentication with Redux Toolkit using onAuthStateChanged?
(1 answer)
Closed 7 months ago.
I am trying to set the auth status for the currently logged-in user using redux-toolkit's createAsyncThunk and firebase's onAuthStatechanged, but I cannot do so. I am trying to implement a private route that can only be accessed if a user is logged in.
*What I have tried
I create an authService.js file where I created a function checkAuthStatus which calls onAuthStateChanged and returns a user if a user is there else null and then from authSlice, I have exported another function checkUserStatus which returns a promise, and when it gets fulfilled the user will be set to the user returned but the returned value is always null even if the user is logged in.
const checkAuthStatus = () => {
onAuthStateChanged(auth, (user) => {
console.log(user);
return user ? user : null;
});
};
const authService = {
registerUser,
loginUser,
checkAuthStatus,
};
export default authService;
export const checkUserStatus = createAsyncThunk('auth/checkAuth', () => {
return authService.checkAuthStatus();
});
.addCase(checkUserStatus.pending, (state, action) => {
state.isLoading = true;
})
.addCase(checkUserStatus.fulfilled, (state, action) => {
state.user = action.payload;
state.isLoading = false;
});
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Outlet, Navigate } from 'react-router-dom';
import { checkUserStatus } from './../features/auth/authSlice';
import Loader from './Loader';
const PrivateComponent = () => {
const { user, isLoading } = useSelector((state) => state.auth);
const dispatch = useDispatch();
useEffect(() => {
dispatch(checkUserStatus());
}, [dispatch]);
if (isLoading) {
return <Loader />;
}
return user ? <Outlet /> : <Navigate to="/login" />;
};
export default PrivateComponent;
Problem
I am not sure why but the function in the authSerice file checkAuthStatus is returning null even if the current user is not null. One more thing is that the user field from the state is not even there in the redux dev tools, check images for more.
Here is my code:-
authService.js authService Page Image
authSlice.js authSlice function || authSlice extrareducer
PrivateComponent.js Private Route component
App.js Routes for app
one more thing I have notice is the user state is not even there as redux dev tools are showing
this is pending
before
this is fulfilled
after
I have changed the code and now the auth is working but on refreshing the page the user status is user get redirected to login page why?
How to set authentication status with firebase using onAuthStateChanged ?
There are many way to achieve this:
Using global store
const userSlice = createSlice({
name: "users",
initialState,
reducers: {
setLoginStatus: (state, action) {
state.loginStatus = action.payload;
}
},
extraReducers: {
[createUser.fulfilled]: (state, action) => {
state.loginStatus = true;
},
[createUser.rejected]: (state, action) => {
state.loginStatus = false;
},
},
});
// trackUserAuth.ts
onAuthStateChanged(auth, (user) => {
if (user) {
store.dispatch(setLoginStatus(true))
} else {
store.dispatch(setLoginStatus(true))
}
});
Using hooks
export const useAuth = () => {
const dispatch = useDispatch();
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
dispatch(setLoginStatus(true))
} else {
dispatch(setLoginStatus(true))
}
});
return unsubscribe;
}, []);
}
Using thunks
export const checkAuthStatus = () => (dispatch) {
const unsubscribe = Firebase.auth().onAuthStateChanged(user => {
if (user) {
dispatch(setLoginStatus(true))
} else {
dispatch(setLoginStatus(true))
}
});
return unsubscribe;
}
My website has two parts one is for registered users and another is for admin.
So after login users are go to dashboard and then suppose they go to a page from dashboard and then they reload the page, after reloading it's still working fine and stay on the current page. here i using user.displayName from useFirebase hook as codition.
But in admin mode after reload the page admin are redirecting to the home,its not staying in the current page.Here i using codition 'admin' from useFirebase hook,admin is true but its not staying in the currrent route after reload.i think may be the loader is not working perfectly there for fetching the data,but i dont undestand how to fix it out.
front end AdminRoute.
const AdminRoute = props => {
const { user, newLoading, admin } = useAuth();
const { children, ...rest } = props;
console.log(newLoading, admin);
const [isLoading, setIsLoading] = useState(false);
// const [isData, setIsData] = useState(false);
useEffect(() => {
if (user) {
setIsLoading(true);
fetch(`http://localhost:3005/users/${user.email}`)
.then(res => res.json())
.then(data => {
localStorage.setItem('userDetails', JSON.stringify(data));
})
.finally(() => setIsLoading(false));
}
}, [user]);
if (isLoading) {
return (
<div className="test10">
<Spinner animation="border" />;
</div>
);
}
return (
<Route
{...rest}
render={({ location }) =>
**admin** ? (
children
) : (
<Redirect
to={{
pathname: '/',
state: { from: location },
}}
></Redirect>
)
}
></Route>
);
};
export default AdminRoute;
here admin is true but still its not staying at the current page after realod but if i use user.displayName which for just users only its works,and staying at the current page after reload.
Server side part,
app.get('/users/:email', async (req, res) => {
const email = req.params.email;
const query = { email: email };
const user = await usersCollection.findOne(query);
let isAdmin = false;
if (user?.role === 'admin') {
isAdmin = true;
}
res.json({ admin: isAdmin, user });
});
I'm trying to make a Username and Password Authentication in a web app that is made with react and firebase.
But I'm really new to firebase and I couldn't find any good documentation about the process, I have read about Firestore but I don't know how to connect it to the authentication method. Any help or hint is appreciated!
Here is the signup function of my /register route.
async function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmationRef.current.value){
return setError('Passwords do not match');
}
try {
setError('')
setLoading(true)
await signup(emailRef.current.value, passwordRef.current.value, usernameRef.current.value)
Home()
} catch {
setError('Failed to create an account')
}
setLoading(false)
}
And this is my 'AuthContext.JSX' code:
import React, { useContext , useEffect, useState } from 'react'
const AuthContext = React.createContext()
import {auth} from '../firebase'
export function useAuth() {
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState()
const [loading, setLoading] = useState(true)
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
setLoading(false)
})
return unsubscribe
}, [])
auth.onAuthStateChanged(user => {
setCurrentUser(user)
})
const value = {
currentUser,
signup,
login
}
return (
<AuthContext.Provider value={value}>
{!loading && children }
</AuthContext.Provider>
)
}
Just to let you know the authentication is working well the only problem is getting the Display Name and exporting it to the home page for display.
I want to display the username on this page
Thanks to Dhamaraj I used the updateProfile() function inside my Register route, and it worked properly for adding a display name to the user which I used on the home page for the profile display.
That is the new function, may it helps somebody with the same issue:
async function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmationRef.current.value){
return setError('Passwords do not match');
}
try {
setError('')
setLoading(true)
await signup(emailRef.current.value, passwordRef.current.value)
auth.currentUser.updateProfile({
displayName: usernameRef.current.value
}).then(() => {
console.log('Username is: ' + auth.currentUser.displayName)
}).catch((error) => {
console.log('An error was occured while updating the profile.')
});
Home()
} catch {
setError('Failed to create an account')
}
setLoading(false)
}