TypeError: auth is not a function after logging in or signing up - reactjs

I'm getting this error after trying to either sign up or login as a pop up
localhost:3000 says TypeError: _auth_base_js__WEBPACK_IMPORTED_MODULE_6__.default.auth is not a function
I'm not sure where the problem is coming from but if you need here is my login page
const Login = ({ history }) => {
const handleLogin = useCallback(
async (event) => {
event.preventDefault();
const { email, password } = event.target.elements;
try {
await app
.auth()
.signInWithEmailAndPassword(email.value, password.value);
history.push("/");
} catch (error) {
alert(error);
}
},
[history]
);
// var { currentUser } = useContext(AuthContext);
// if (currentUser) {
// return <Redirect to="/" />;
// }
and here is my signup page:
const SignUp = ({ history }) => {
const handleSignUp = useCallback(
async (event) => {
event.preventDefault();
const { email, password } = event.target.elements;
try {
await app
.auth()
.createUserWithEmailAndPassword(email.value, password.value);
history.push("/");
} catch (error) {
alert(error);
}
},
[history]
);
Sorry for asking too much but I have looked everywhere and tried every possible solution, but none worked for me.

i solved it by routing the files to the required pages

Related

useState does not update the state within .catch after dispatching of asynk thunk

In the following code setError does not update error in the catch after async thunk from redux-toolkit.
const [error, setError] = useState("");
const handleLogin = () => {
dispatch(userLogin({ email, password }))
.unwrap()
.then(() => {
if (userInfo) {
navigate("/profile");
}
})
.catch((err) => {
setError(err) // does not work
});
};
<button onClick={handleLogin}>Login</button>
export const userLogin = createAsyncThunk(
"auth/login",
async ({ email, password }, thunkAPI) => {
try {
const { data } = await userLoginRequest(email, password);
return data;
} catch (error) {
return thunkAPI.rejectWithValue(ERR_USER_LOGIN);
// ERR_USER_LOGIN is just a constant string from another file
}
}
);
I know that useState does not apply changed immediatly but in my case it ignores changes at all. I suppose that the problem can be related to the scope or something like this. So I've tried to use additional callback which I sent as a parameter and change the state through it but it also does not work.
Your userLogin function actually has caught the error, making handleLogin catch not catch anything.
You can throw the error within userLogin, so handleLogin can catch the error by itself.
export const userLogin = createAsyncThunk(
"auth/login",
async ({ email, password }, thunkAPI) => {
try {
const { data } = await userLoginRequest(email, password);
return data;
} catch (error) {
thunkAPI.rejectWithValue(ERR_USER_LOGIN);
// Add this
throw error;
}
}
);

React Firebase is not returning error message even after giving wrong input

I am using React Firebase hook to log in to my website. when trying to log in with the wrong email or password in the login form, an error message will be returned from the React firebase hook. But even after giving the wrong input, an error message is not returning
const Login = () => {
const [signInWithEmailAndPassword, error] =
useSignInWithEmailAndPassword(auth);
const location = useLocation();
const navigate = useNavigate();
const from = location?.state?.from?.pathname || '/';
if (error) {
return (
<div>
<p>Error: {error.message}</p>
</div>
);
}
const handleLogIn = (e) => {
e.preventDefault();
const email = e.target.email.value;
const password = e.target.password.value;
signInWithEmailAndPassword(email, password)
e.target.reset();
navigate(from, { replace: true })
}
You are using signInWithEmailAndPassword hook incorrectly.
signInWithEmailAndPassword returns an array & 3th index is of error message.
You can follow this: https://github.com/CSFrequency/react-firebase-hooks/blob/master/auth/README.md#usesigninwithemailandpassword
const [
signInWithEmailAndPassword,
user,
loading,
error,
] = useSignInWithEmailAndPassword(auth);
Since, useSignInWithEmailAndPassword returns an Array, We need to extract/destructure the value from respective index.
Apart from that, You must also use loading to display whether firebase is still authorizing the request or not (Loading State).
The signInWithEmailAndPassword appears to be an async function and your code isn't waiting for the returned Promise to resolve. I'm guessing you are seeing the navigate("/"); called and the app is navigating to the home page.
const handleLogIn = (e) => {
e.preventDefault();
const email = e.target.email.value;
const password = e.target.password.value;
signInWithEmailAndPassword(email, password); // <-- no waiting for promise
e.target.reset();
navigate(from, { replace: true }); // <-- navigate away
};
useSignInWithEmailAndPassword
export default (auth: Auth): EmailAndPasswordActionHook => {
const [error, setError] = useState<AuthError>();
const [loggedInUser, setLoggedInUser] = useState<UserCredential>();
const [loading, setLoading] = useState<boolean>(false);
const signInWithEmailAndPassword = async (
email: string,
password: string
) => {
setLoading(true);
setError(undefined);
try {
const user = await firebaseSignInWithEmailAndPassword(
auth,
email,
password
);
setLoggedInUser(user);
} catch (err) {
setError(err as AuthError);
} finally {
setLoading(false);
}
};
const resArray: EmailAndPasswordActionHook = [
signInWithEmailAndPassword,
loggedInUser,
loading,
error,
];
return useMemo<EmailAndPasswordActionHook>(() => resArray, resArray);
};
The handleLogin handler should probably wait for the Promise to settle so any errors can be returned by the hook. It turns out though that signInWithEmailAndPassword also doesn't return any resolve/rejected values, so there's no way to know the authentication was successful from within the handleLogIn callback function, the component will need to use the hook's returned loading and loggedInUser states to determine if it is safe to navigate.
Example:
const Login = () => {
const [
signInWithEmailAndPassword,
loggedInUser,
loading,
error,
] = useSignInWithEmailAndPassword(auth);
const location = useLocation();
const navigate = useNavigate();
const from = location?.state?.from?.pathname || '/';
useEffect(() => {
if (!loading && loggedInUser) {
navigate(from, { replace: true });
}, [loggedInUser, loading, navigate, from]);
if (error) {
return (
<div>
<p>Error: {error.message}</p>
</div>
);
}
const handleLogIn = (e) => {
e.preventDefault();
const email = e.target.email.value;
const password = e.target.password.value;
signInWithEmailAndPassword(email, password)
e.target.reset();
}
...

React Router Dom v6 useNavigate to Conditional Path Directory After Login

Here I am passing navigate from login to useFirebase
let navigate = useNavigate();
const handleLoginSubmit = (e) => {
loginUser(loginData.email, loginData.password, navigate);
e.preventDefault();
// alert('Login Successful');
}
This is loginUser control in useFirebase
// user login
const loginUser = (email, password, navigate) => {
setIsLoading(true);
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const destination = navigate?.state?.from || '/';
navigate(destination);
// navigate('/appointment');
// Signed in
const user = userCredential.user;
// ...
setAuthError('');
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
setAuthError(error.message);
})
.finally(() => setIsLoading(false));
}
I am trying to add a condition rendering in navigate. When the user will log in it will redirect to which components, where he was trying to go before PrivateRoute, interfere to log in the user
This assumes you are capturing the route the user was originally attempting to access. If your code is not doing this then this is the gist for capturing a redirect "referrer" to use after authenticating.
Example:
const AuthWrapper = ({ authenticated }) => {
const location = useLocation();
return authenticated
? <Outlet />
: <Navigate to="/login" replace state={{ from: location }} />;
}
In the code passing the navigate function and handling the login submission, access the passed referrer route state here, and pass this along to the loginUser callback.
const navigate = useNavigate();
const { state } = useLocation();
const from = state?.from || "/";
const handleLoginSubmit = (e) => {
e.preventDefault();
loginUser(loginData.email, loginData.password, navigate, from);
};
Access the passed from referrer value in the loginUser callback.
const loginUser = (email, password, navigate, destination) => {
setIsLoading(true);
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
navigate(destination);
// Signed in
const user = userCredential.user;
// ...
setAuthError('');
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
setAuthError(error.message);
})
.finally(() => setIsLoading(false));
};
It may be a little more clean to instead pass an onAuthSuccess callback, but this is subjective.
const navigate = useNavigate();
const { state } = useLocation();
const from = state?.from || "/";
const handleLoginSubmit = (e) => {
e.preventDefault();
loginUser(loginData.email, loginData.password, () => navigate(from));
};
...
const loginUser = (email, password, onAuthSuccess) => {
setIsLoading(true);
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
onAuthSuccess();
// Signed in
const user = userCredential.user;
// ...
setAuthError('');
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
setAuthError(error.message);
})
.finally(() => setIsLoading(false));
};

useNavigate not working react-router-dom v6

I'm using react-router-dom v6 and I'm accessing the from value from the location object and it gives the pathname but when executing navigate(from,{replace:true}) it does not work.
const navigate = useNavigate();
const { state } = useLocation();
const from = state ? state.from.pathname : '/';
const [isDone, setIsDone] = useState(false);
useEffect(() => {
if (isDone) {
navigate(from, { replace: true }); //not working
}
}, [isDone]);
const Submit = async (e) => {
e.preventDefault();
let data = { email, password };
if (!email || !password) {
setMessage('Please Enter All Fields');
} else {
setLoading(true);
return await axios
.post('/signin', data)
.then((res) => {
if (res.data.message === 'Invalid Credentials') {
setMessage('Invalid Credentials');
}
if (res.data.message === 'Logged In') {
setIsDone(true);
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
setLoading(false);
});
}
After fixing your CSB I see the redirect working. The issue is that the auth value in App doesn't change because your login flow doesn't set the logged_in_status value stored in localStorage. The result is that the user is bounced right back to the "/signin" route.
You should also be serializing/deserializing the data you save/access to/from localStorage.
App
const auth = JSON.parse(localStorage.getItem('logged_in_status'));
...
useEffect(() => {
const checkAuthStatus = async () => {
return await axios.get("/loginstatus").then((res) => {
if (res.data.message === "No Token") {
localStorage.setItem("logged_in_status", JSON.stringify(false));
}
if (res.data.message === "Invalid Token") {
localStorage.setItem("logged_in_status", JSON.stringify(false));
}
if (res.data.message === "Valid Token") {
localStorage.setItem("logged_in_status", JSON.stringify(true));
}
});
};
checkAuthStatus();
});
Use a boolean expression for checking the auth value in your route wrappers.
const PublicRoute = () => {
if (auth) {
return <Navigate to="/" replace={true} state={{ from: location }} />;
}
return <Outlet />;
};
const PrivateRoute = () => {
if (!auth) {
return (
<Navigate to="/signin" replace={true} state={{ from: location }} />
);
}
return <Outlet />;
};
Signin
Here you just need to set a true "logged_in_status" into localStorage upon successful authentication. There's also no real need I see for setting the done state; you can simply issue the imperative redirect when authenticated.
const Submit = async (e) => {
e.preventDefault();
let data = { email, password };
if (!email || !password) {
setMessage("Please Enter All Fields");
} else {
setLoading(true);
return await axios
.post("/signin", data)
.then((res) => {
if (res.data.message === "Invalid Credentials") {
setMessage("Invalid Credentials");
}
if (res.data.message === "Logged In") {
localStorage.setItem("logged_in_status", JSON.stringify(true)); // <-- set localStorage
navigate(from, { replace: true }); // <-- redirect
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
setLoading(false);
});
}
};
I think the issue is with '/', remove it from the URL and try.
navigate(from.replace('/', '') , { replace: true });
I just simply use:
import { useNavigate } from 'react-router-dom';
...
const navigate = useNavigate();
...
<Button onClick={() => navigate('../login', { replace: true })}>LogOut</Button>
So, I added ../ before the route and the replace: true.
Reference:- React Router v6...

Firebase Authentication operations in React

When I check the user it always turns data on checkUserAuth() function and isLogin is true .Then When I push the logout button, isLogin becomes false instantly and becomes true again.How to use checkUserAuth function??
Thank you for any assistance
//Navbar.jsx
import React, { useState, useEffect } from "react";
import { Link, useHistory } from "react-router-dom";
import Firebase from "../firebase/firebase.utils";
const Navbar = () => {
const history = useHistory();
const [isLogin, setIsLogin] = useState(false);
useEffect(() => {
Firebase.checkUserAuth().then((user) => {
if (user) {
setIsLogin(true);
}
});
}, [isLogin]);
const logout = () => {
if (isLogin === true) {
Firebase.signOut().then(() => {
setIsLogin(false);
history.push("/");
});
}
};
///Firebase
const Firebase = {
// auth
loginWithEmail: async (email, password) => {
return await firebase
.auth()
.signInWithEmailAndPassword(email, password);
},
signupWithEmail: async (email, password) => {
return await firebase
.auth()
.createUserWithEmailAndPassword(email, password);
},
signOut: async () => {
return await firebase.auth().signOut()
.catch((err) => console.log(err.message));
},
checkUserAuth: async () => {
return await firebase.auth().onAuthStateChanged(data => data);
},
// firestore
createNewUser: (userData) => {
return firebase
.firestore()
.collection("users")
.doc(`${userData.uid}`)
.set(userData);
},
};
export default Firebase;

Resources