React Native (React Navigation)<> Firebase login screen - javascript

I'm using Firebase to keep track of all the users. I was able to connect Firebase. User registration is working fine.
I'm having issues with logging the users. When I enter login and password, the app doesn't redirect me to the right screen, and also throws this warning [Unhandled promise rejection: TypeError: navigation.navigation is not a function. (In 'navigation.navigation("myProfile")', 'navigation.navigation' is undefined)]
Here is how I do it
import { useNavigation } from "#react-navigation/native";
import React, { useEffect, useState } from "react";
import { View, ...} from "react-native";
import { auth } from "../firebase";
const Profile = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const navigation = useNavigation();
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
if (user) {
navigation.navigation("myProfile");
}
});
return unsubscribe;
}, []);
const signIn = () => {
auth
.signInWithEmailAndPassword(email, password)
.then((userCredentials) => {
const user = userCredentials.user;
console.log("Sign In user.email = " + user.email);
})
.catch((error) => alert(error.message));
};
//more code
I also tried this, but it didn't help
import React, { useEffect, useState } from "react";
import { View, ...} from "react-native";
import { auth } from "../firebase";
const Profile = ({navigation}) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
if (user) {
navigation.navigation("myProfile");
}
});
return unsubscribe;
}, []);
//more code
I'm not sure if I need to navigation.navigation("myProfile") onPress or it has to be inside of the the useEffect

Use
navigation.navigate("myProfile")
instead of
navigation.navigation("myProfile");
Also you can destruct your hook object like this
const { navigate } = useNavigation()
in order to just write
navigate("myProfile")
I'm not sure if I need to navigation.navigation("myProfile") onPress or it has to be inside of the the useEffect
Most of the cases you should move the user to home screen (logged in user screen) when the signIn function returns true and the user is logged in, so in this case I think you have to use navigate("myProfile") inside of
auth
.signInWithEmailAndPassword(email, password)
.then((userCredentials) => {
...your code
navigation.navigate("myProfile")
})

Related

Reactjs Hooks Context Provider with no token present

Hello I have a reactjs context which checks the localstorage token and then passes data down from it to the other componenets. However if a user tries to load a page without having access I want it to navigate back to the login component. However I keep getting this error "{message: 'Invalid token specified'}" Because the token doesn't exist in this scenario. How can I correctly make this redirect and work if the token doesn't exist at all?
import { createContext, useState, useEffect } from "react";
import jwt_decode from "jwt-decode";
const UserContext = createContext({});
export const UserProvider = ({ children }) => {
const [firstName, setFirstName] = useState();
const [lastName, setLastName] = useState();
const [email, setEmail] = useState();
function checkAuth() {
const token = localStorage.getItem("access_token");
if (localStorage.getItem("access_token") === '') {
navigate('/auth');
return false;
}
const authData = jwt_decode(token);
setFirstName(authData.firstname);
setLastName(authData.lastName);
setEmail(authData.email);
}
useEffect(()=>{
checkAuth
},[checkAuth])
return (
<UserContext.Provider value={{
firstName, setFirstName,
lastName, setLastName,
email,setEmail
}}>
{children}
</UserContext.Provider>
)
}
export default UserContext;

using GraphQL Mutations with Apollo Client and Redux Toolkit

I don't know If I'm doing this the right way, it's the first time I've implemented GraphQL Apollo Client with Redux Toolkit.
So I have a Thunk:
import { createAsyncThunk } from "#reduxjs/toolkit";
import { useMutation } from "#apollo/client";
import {LOGIN_USER} from "../../graphql/mutations/auth";
export const Authenticate = createAsyncThunk(
"auth/login",
async (data, thunkAPI) => {
const {email, password} = data;
const [login, { loading, error, data: user }] = useMutation(LOGIN_USER,{
variables: {
email,
password
}
});
await login();
if (error) {
return thunkAPI.rejectWithValue(error);
}
console.log(user);
return user;
}
)
the mutation looks like this:
import {gql} from "graphql-tag";
export const LOGIN_USER = gql`
mutation login($email: String!, $password: String!) {
login(email: $email, password: $password) {
id
email
name
token
}
}
`;
However, In my component, when I dispatch the action, nothing happens, I've checked the network tab, but there are no requests to my apollo server.
import {Authenticate} from "../../features/user/userActions";
import {useDispatch, useSelector} from "react-redux";
const handleSubmit = async (event) => {
event.preventDefault();
dispatch(Authenticate({email, password}));
};
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
I'd appreciate any provided help and support

Firebase and React TypeError: firebase.auth(...).onAuthStateChanged is not a function

I am trying to use the onAuthStateChanged trigger to unsubscribe but I keep getting:
Uncaught TypeError: (0 , firebase_util__WEBPACK_IMPORTED_MODULE_0_.getModularInstance)(...).onAuthStateChanged is not a function
below is my Authcontext.js
import React ,{useEffect, useState ,useContext} from 'react';
import { auth } from '../api/firebase';
const AuthContext = React.createContext();
export function useAuth() {
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null);
const [loading,setLoading] = useState(true);
function register (email,password) {
return auth.createUserWithEmailAndPassword(email,password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user);
});
return unsubscribe;
}, []);
const value = {
currentUser,
register,
}
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
}
You are not subscribing to the StateChange correctly , try the following
React.useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged((user) => { // detaching the listener
if (user) {
// ...your code to handle authenticated users.
} else {
// No user is signed in...code to handle unauthenticated users.
}
});
return () => unsubscribe(); // unsubscribing from the listener when the component is unmounting.
}, []);
I have faced the same error when I was working on react native app and because of firebase version change they have update some methods.
I have resolved this by below code and firebase verison is ^9.6.11.
you do not need to pull onAuthStateChanged
import { getAuth } from "firebase/auth";
export const yourfunc = () => {
const auth = getAuth();
auth.onAuthStateChanged((user) => {
console.log(user)
}
}

How can I go about trying to use onSnapshot in my user context? I would like to get real time updates of notifications (like facebook etc.)

I am trying to get realtime notifications or user profile updates from firebase. I understand I need to use onSnapshot however, I tried before and it wasn't unsubscribing. If you logged out and loggin in as another user, it would sometimes get the profile data of the user logged in previously, which is an AWFUL bug to have.
So basically I have two context providers:
AuthProvider (stores (currentUser) auth email, uid etc.)
UserProvider (stores (userData) firestore data, such as profile picture, username, first name, surname etc.)
How can I go about subscribing to the userData information but then ensuring it unsubscribes when the auth state changes? As I have failed to this at every attempt.
AuthProvider:
import React, { useContext, useState, useEffect } from "react";
import { auth, db } from "../firebase";
const AuthContext = React.createContext();
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);
}
function logout() {
return auth.signOut();
}
function resetPassword(email) {
return auth.sendPasswordResetEmail(email);
}
function updateEmail(email) {
return currentUser.updateEmail(email);
}
function updatePassword(password) {
return currentUser.updatePassword(password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
setSearchQueryState,
login,
signup,
logout,
resetPassword,
updateEmail,
updatePassword,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
UserProvider:
import React, { useContext, useState, useEffect } from "react";
import { getUserByUserId } from "../services/firebase";
import { useAuth } from "./AuthContext";
const UserContext = React.createContext();
export function useUser() {
return useContext(UserContext);
}
export function UserProvider({ children }) {
const { currentUser } = useAuth();
const [userData, setUserData] = useState();
const [loading, setLoading] = useState(true);
useEffect(async () => {
if (currentUser) {
const data = await getUserByUserId(currentUser.uid);
setUserData(data);
setLoading(false);
} else {
setUserData();
setLoading(false);
}
}, [currentUser]);
const value = {
userData,
};
return (
<UserContext.Provider value={value}>
{!loading && children}
</UserContext.Provider>
);
}
The firebase call I imported into UserProvider
import { auth, db } from "../firebase";
// get user from the firestore where userId === userId (passed from the auth)
export async function getUserByUserId(userID) {
const result = await db.collection("users").doc(userID).get();
const user = result.data();
return user;
}
Thank you in advance!
So currently, when this useEffect in my userAuth is causing me to sometimes log in as other users:
import { auth, db } from "../firebase";
import { getUserByUserId } from "../services/firebase";
import { useAuth } from "./AuthContext";
const UserContext = React.createContext();
export function useUser() {
return useContext(UserContext);
}
export function UserProvider({ children }) {
const { currentUser } = useAuth();
const [userData, setUserData] = useState();
const [loading, setLoading] = useState(true);
//THIS USE EFFECT LISTENS TO SNAPSHOT DATA--------
useEffect(async () => {
let usersnapshot;
if (currentUser) {
usersnapshot = db.collection("users").doc(currentUser.uid);
usersnapshot.onSnapshot((doc) => {
setUserData(doc.data());
setLoading(false);
});
} else {
setLoading(false);
setUserData();
return usersnapshot;
}
}, [currentUser]);
//--------------------------
const value = {
userData,
};
return (
<UserContext.Provider value={value}>
{!loading && children}
</UserContext.Provider>
);
}
I would suggest to detach the listener when the currentUser changes. Can you try to change this part of your code:
useEffect(async () => {
let usersnapshot;
let unsubscribe;
if (currentUser) {
usersnapshot = db.collection("users").doc(currentUser.uid);
unsubscribe = usersnapshot.onSnapshot((doc) => {
setUserData(doc.data());
setLoading(false);
});
} else {
setLoading(false);
setUserData();
return usersnapshot;
}
return unsubscribe;
}, [currentUser]);
What we are doing here that we save the unsubscribe call to a variable in the useEffect and call it when the currentUser changes. That should unsibscribe the onSnapshot each time a user changes.
First, you should use Firestore rules, to deny any request for user data by different users, e.g.:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{user} {
allow read, write: if
request.auth.uid == request.resource.data.ownerID
}
}
}
Second, I am not sure if your unsubscribe call works like this in a useEffect. instead of return unsubscribe; try return () => unsubscribe();

'login' is not defined error happens in React.js

I made frontend app in React.js.
I wrote codes in App.js of frontend like
import React, { Fragment, useState, useEffect, Component, View } from 'react';
import axios from 'axios';
import Routes from '../src/components/Routes';
import TopNavigation from './components/topNavigation';
import SideNavigation from './components/sideNavigation';
import Footer from './components/Footer';
import './index.css';
import Router from './Router';
const App = () => {
const [user, setLogin] = useState(null)
const [report, setReport] = useState(null)
useEffect(()=>{
login().then(user => setLogin(user))
}, [])
useEffect(()=>{
getReport().then(report => setReport(report))
}, [])
return <div>
{user != null? <p>name: {user.name}</p>:<button>Login</button>}
</div>
}
export default App;
I wrote in this code login().then(user => setLogin(user)) whether user already logined or not.
Login system was made in Django,so I want to use it.I think React has login method but I really cannot understand what is wrong.How should I fix this?
I can see nowhere login is defined in your code. If you've written login on other files, you should import it.
Actually, I cannot understand what you mean by this - "I think React has login method but ...". React doesn't support any predefined login method.
You should define login method yourself something like this.
const API_URL = 'some url';
const login = async (body) => {
const response = await axios.post(`${API_URL}/login`, body);
return response.json();
};
const App = () => {
const [user, setLogin] = useState(null);
const [report, setReport] = useState(null);
useEffect(() => {
login({
email: 'email#some.com',
password: 'some password'
}).then((user) => setLogin(user));
}, []);
useEffect(() => {
getReport().then((report) => setReport(report));
}, []);
};

Categories