App loading forever - firebase.auth().onAuthStateChanged - firebase

I have a simple component that checks if the user is logged in or not.
20% of the times this works correctly, but the other 80%, the page is just loading forever as firebase.auth().onAuthStateChanged is never fired or it is fired after minutes of loading.
What could be happening?
class Loading extends Component {
componentDidMount() {
this.checkIfLoggedIn();
}
checkIfLoggedIn = () => {
console.warn("checking if logged in")
firebase.auth().onAuthStateChanged(
user => {
console.warn('AUTH STATE CHANGED CALLED ', user)
if (user) {
console.log("there is indeed a user")
this.props.navigation.navigate('Main');
} else {
console.log("go authenticate")
this.props.navigation.navigate('Auth');
}
}
);
};
render() {
return (
<View style={styles.container}>
<Text>Please wait there</Text>
<ActivityIndicator size="large" />
</View>
);
}
}

I figured it out. I was navigating to an unexisting component.

Related

this.props.route.params returns value as undefined

I'm building a barcode reader app that scans that qr code and then takes data and is used as a key to fetch an object from firebase. In order the data to be used as a key I need to pass through another screen but when I check console log it's cameback that the scanned key is undefined.
The itself barcode scanner works perfectly.
Barcode class :
export class BarCodeScannerScreen extends Component{
state = {
CameraPermissionGranted: null,
}
async componentDidMount() {
// Ask for camera permission
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ CameraPermissionGranted: status === "granted" ? true : false });
};
barCodeScanned = ({ data }) => {
//Access the Data
alert(data); // shows the scanned key
this.props.navigation.navigate('Info', {
item: data, }); // but then it's dissapears in here.
};
render(){
const { CameraPermissionGranted } = this.state;
if(CameraPermissionGranted === null){
// Request Permission
return(
<View style={styles.container}>
<Text>Please grant Camera permission</Text>
</View>
);
}
if(CameraPermissionGranted === false){
// Permission denied
return (
<View style={styles.container}>
<Text>Camera Permission Denied.</Text>
</View>
);
}
if(CameraPermissionGranted === true){
// Got the permission, time to scan
return (
<View style = {{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<BarCodeScanner
onBarCodeScanned = {this.barCodeScanned }
style = {{
height: DEVICE_HEIGHT/1.1,
width: DEVICE_WIDTH,
}}
>
</BarCodeScanner>
</View>
);
}
}
}
Here is my Info screen that receives the information :
export default class InfoScreen extends Component {
constructor(props){
super(props);
this.state={
productlist:[],
scannedkey: this.props.route.params.item
} }
async componentDidMount(){
firebase.database().ref(`product/${ this.state.scannedkey}`).on(
"value",
(snapshot) => {
var list = [];
snapshot.forEach((child) => {
list.push({
key: child.key,
title: child.val().title,
//details: child.val().details,
//price: child.val().price
});
});
this.setState({ productlist: list });
},
(error) => console.error(error)
);
}
componentWillUnmount() {
if (this.valuelistener_) {
this.valueRef_.off("value", this.valuelistener_)
}}
render() {
console.log(this.state.scannedkey); // console log shows that scanned key is undefined
return(
<View style={styles.container}>
<Text>Hey</Text>
<Text>{this.state.productlist.title}</Text>
</View>
);}}
App.js
export default function App() {
const Drawer=createDrawerNavigator();
return (
<Provider store={store}>
<NavigationContainer>
<Drawer.Navigator initialRouteName="Barcode">
<Drawer.Screen name="Barcode" component={BarCodeScannerScreen} />
<Drawer.Screen name="Info" component={InfoScreen} />
</Drawer.Navigator>
</NavigationContainer>
</Provider>
);
}
I ussualy use function components to navigate through but with class components it's a little tricky for me. Perhaps I missed something?
So far I 've tried :
this.props.navigation.navigate('Info', {
item: JSON.stringify(data) , });
And it didn't work.
I will be grateful for your help.
Try to use item directly from props, not from state
in your componentDidMount call where you supply from state the scannedKey, supply it from props
firebase.database().ref(`product/${this.props.route.params.item}`)....
you are also calling this.props instead of props directly in your state inside your constructor, which have direct access to it, that's why you can call super(props) and not super(this.props), I am not sure if this is the issue, but in react docs says don't copy props to state because they get ignored, and it's bad practice my friend.
check this link, in the big yellow note what I am reffering to
https://reactjs.org/docs/react-component.html#constructor

react native error: "nothing was returned from render"

This is my sign out function which should redirect the user to the login screen after logout. But it is not working and I am getting the error "nothing was returned from this render".
const signout= async() => {
setShowLoading(true);
try {
const a= await auth().signOut().then(()=>{
console.log(a);
setUser(null)
setShowLoading(true)
if(!user)
{
return navigation.navigate('Login')
}
}
);
}
catch (e) {
setShowLoading(false);
Alert.alert(
e.message
);
}
};
and this is my return in function
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Welcome {user.email}</Text>
<Button title="logout" onPress={()=>signout()}/>
{showLoading &&
<View style={styles.activity}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
}
</View>
);
Nothing was returned from render function means, that one of you Components has nothing returned to it to render. In your codeblock's case, in a case where there is user, nothing is being returned. Either you edit renderMethod to return Home screen or you can navigate user to a different page before user is set or unset depending on your requirement. Either way, react must have something to render to the screen or it will throw an error like this.

react native firebase authentication

In react native with firebase I get a chat app code. It used a button to show my registered friends, but I want to check when this button click user is logged in or not.
This is the button code in render function
render() {
return (
<View style={styles.containerl}>
<StatusBar barStyle="light-content" backgroundColor="red" />
<TouchableOpacity>
<Text
style={styles.buttonStyle}
onPress={() => this.props.navigation.navigate("Friendlist")}
>
SHOW FRIEND LIST
</Text>
</TouchableOpacity>
</View>
);
}
I want to add this firebase authentication code in to Show Friend List text press.
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user logged')
}
});
Can anyone help me?
You can do like below. Add a flag to check whether the user logged in or not
state = {
isUserLogged: false
}
constructor(props) {
super(props);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({
isUserLogged: true
})
} else {
this.setState({
isUserLogged: false
})
}
});
}
render() {
return (
<View style={styles.containerl}>
<StatusBar barStyle="light-content" backgroundColor="red" />
<TouchableOpacity>
<Text
style={styles.buttonStyle}
onPress={() => {
if (this.state.isUserLogged) {
this.props.navigation.navigate("Friendlist")
} else {
console.log('user not logged')
}
}
}
>
SHOW FRIEND LIST
</Text>
</TouchableOpacity>
</View>
);
}
In order to show whether a user is logged in or not, you'll need to attach a variable to the user state. So, your authentication code:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user logged')
}
});
essentially, will put this method in either the constructor() or the componentDidMount() method.
From there, you'll need to set the state, like -
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ userLoggedIn: true });
console.log('user logged')
}
});
and in your render() you can attach conditions to this.state.userLoggedIn on your onPress() method accordingly.
If you need to send the logged in state to your <Friendlist/> component, you'll be required to do -
this.props.navigation.navigate("Friendlist", {userLoggedIn: this.state.userLoggedIn})
and in your <Friendlist/> component you can fetch it from this.props.navigation.state.params.userLoggedIn

TypeError: Cannot read property 'uid' of null

I am trying to log in with a phone number in my app with firebase but I am facing issue with the login process. I'm not able to login with a phone number in firebase but if I register with a phone number and redirect to the homepage it's working properly. I am using the same method to login, but I got the issue like TypeError: Cannot read property 'uid' of null but I an successfully getting all the console values. I don't know what is being the issue here. But that error is displaying in 3 times repeatedly,
Here is my code:
renderLoginButton() {
if (this.props.loading) {
return (
<Spinner size="large" />
);
}
return (
<Button
style={{ alignSelf: 'flex-start' }}
onPress={this.onLoginBtnClicked.bind(this)}
>
Login
</Button>
);
}
onLoginBtnClicked() {
const { contact, password } = this.props;
const error = Validator('password', password) || Validator('contact', contact);
if (error !== null) {
Alert.alert(error);
} else {
console.log('else');
// this.props.loginUser({ contact, password});
const mobileNo = '+91'+contact;
firebase.auth().signInWithPhoneNumber(mobileNo)
.then(confirmResult =>
console.log(confirmResult),
curr = firebase.auth(),
console.log("curr"+JSON.stringify(curr)),
this.setState({ data: curr}),
NavigationService.navigate('Home')
)
.catch(error => console(error.message) );
}
}
CustomDrawerComponent.js
import React, { Component } from 'react';
import { View, Image, Text } from 'react-native';
import { DrawerItems } from 'react-navigation';
import { connect } from 'react-redux';
import { fetchUserDetails } from '../actions';
class CustomDrawerContentComponent extends Component {
state = {
uri: '',
isfailed: ''
}
componentWillMount() {
this.props.fetchUserDetails();
}
componentWillReceiveProps(nextProps) {
let uri = '';
if (nextProps.ProfilePic !== '') {
uri = nextProps.ProfilePic;
this.setState({ uri, isfailed: false });
} else {
uri = '../images/ic_person_24px.png';
this.setState({ uri, isfailed: true });
}
this.setState({ uri });
}
renderProfileImage() {
if (!this.state.isfailed) {
return (
<Image
style={styles.profileImageStyle}
source={{ uri: (this.state.uri) }}
/>
);
}
return (
<Image
style={styles.profileImageStyle}
source={require('../images/ic_person_24px.png')}
/>
);
}
render() {
console.log('Profile Pic :: ', this.props.ProfilePic);
return (
<View style={styles.container}>
{this.renderProfileImage()}
<Text style={styles.textStyle}>
{this.props.name} - {this.props.category}
</Text>
<DrawerItems {...this.props} />
</View>
);
}
}
const styles = {
container: {
flex: 1,
paddingLeft: 10
},
textStyle: {
fontSize: 14,
textAlign: 'left',
color: '#000000'
},
profileImageStyle: {
alignSelf: 'flex-start',
marginTop: 16,
padding: 10,
width: 40,
height: 40,
borderRadius: 75
}
};
const mapStateToProps = state => {
const { userprofile } = state;
return userprofile;
};
export default connect(mapStateToProps, { fetchUserDetails })(CustomDrawerContentComponent);
callStack:
Why does the user return as undefined (or even null)?
You know there’s a logged in user, you just logged in, heck, you can even see the user object in chrome dev tools.
Then why is it still returning undefined? There’s a straight answer to it.
You’re fetching the user object BEFORE that object is ready to be used.
Now, this can happen because of several different reasons, but if you follow this 2 "rules" you won’t see that error again.
Rule #1: Move it out of the constructor()
When you have something like:
constructor(){
this.userId = firebase.auth().currentUser.uid
}
Over half of the time that page loads, the constructor is going to try to get the user before the user is ready, the app is blocking it because the page isn’t fully loaded, so you’re going to be trying to access uid of a property that just isn’t there yet.
When you get your page fully loaded, you can now call to get the currentUser.uid
Rule #2: Make it an Observable
There’s another approach you can take, that previous Firebase call we just made: firebase.auth().currentUser is synchronous. We can make it asynchronous by subscribing to the auth observable instead.
/**
* When the App component mounts, we listen for any authentication
* state changes in Firebase.
* Once subscribed, the 'user' parameter will either be null
* (logged out) or an Object (logged in)
*/
componentDidMount() {
this.authSubscription = firebase.auth().onAuthStateChanged((user) => {
this.setState({
loading: false,
user,
});
});
}
/**
* Don't forget to stop listening for authentication state changes
* when the component unmounts.
*/
componentWillUnmount() {
this.authSubscription();
}
render() {
// The application is initialising
if (this.state.loading) return null;
// The user is an Object, so they're logged in
if (this.state.user) return <LoggedIn />;
// The user is null, so they're logged out
return <LoggedOut />;
}
}
Source article: Why does Firebase return undefined when fetching the uid?
A good tutorial for React Native will be here: Getting started with Firebase Authentication on React Native
Since, your code did not show much, I hope you make an update to your question to show more code, so I might be able to look through.

Converting circular structure to JSON react-navigation with firebase

Hye guys.. im trying to use react-navigation and firebase in my project.
Im using this awesome boilerplate :-
https://github.com/jhen0409/react-native-boilerplate
in my navigator.js
import { StackNavigator } from 'react-navigation';
import Home from './containers/Home';
import MainScreen from './containers/MainScreen';
import HelpScreen from './containers/HelpScreen';
const AppNavigator = new StackNavigator(
{
Home: { screen: Home },
MainScreen: { screen: MainScreen },
HelpScreen: { screen: HelpScreen }
},
{
headerMode: 'screen'
},
);
export default AppNavigator;
and then in my landing screen which is Home.js
#firebaseConnect()
#connect(
state => ({
nav: state.nav.routes
}),
dispatch => bindActionCreators(userActions, dispatch),
)
export default class Home extends Component {
componentDidMount() {
this.props.firebase.auth().onAuthStateChanged( user => {
if(user) {
//check route stack in redux store
if(this.props.nav[this.props.nav.length-1].routeName !== 'MainScreen') {
this.props.navigation.navigate('MainScreen');
}
this.props.firebase.updateProfile({ lastLogin: new Date() });
user.getIdToken().then( t => this.props.userToken(t) );
} else {
this.props.firebase.auth().signInAnonymously()
.then((user) => {
console.log('user successfully sign in anonymously', user);
// Insert user record to firebase
this.props.firebase.updateProfile(
{
name: 'Anonymous'
}
)
})
.catch(
(error) => {
console.log('error ', error)
})
}
})
}
render() {
return (
<View />
);
}
}
and inside my MainScreen.js
#firebaseConnect(['/helpDetails'])
#connect(
(state, props) => {
return({
})
}
)
export default class MainScreen extends Component {
logout = () => {
this.props.navigation.goBack();
this.props.firebase.logout();
console.log('logout!');
}
render() {
return (
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={() => this.logout()}>
<Text>LOG OUT</Text>
</TouchableOpacity/>
</View>
)
}
}
everything is going fine when user open the apps.. but it start to give this red screen when I click the logout.. if I change firebaseConnect inside Mainscreen from
#firebaseConnect(['/helpDetails'])
TO
#firebaseConnect([])
then everything is working fine..
can anyone help me what im doing wrong here? thanks!
I think this is not a problem of you, but of the library. I have the same issue. Thank god this is only happening while in developer mode (in release everthing works fine).
When I try it without devtools, it works. In my opinion react-redux-firebase is doing some weird stuff when logging out and creates (maybe just for one second) a circular JSON-structure. In JavaScript itself this isn't a big problem, but when you want to stringify it (which is done to display it in your devtools), then the circular structure cannot be converted to a String. Hope to see a fix for that soon from the devs.
Related Issue: Github Issue react-redux-firebase

Resources