react native: run spinner until ListView rendering - firebase

in my app I pull data from Firebase and render them in a ListView. I want that the spinner will run until the entire list will appear.
I added the a view with a conditions that show if the state.loading is 'true', but if I change it in componentDidMount function does not work because the list is not yet displayed
Here is my code:
module.exports = React.createClass({
getInitialState() {
return({
loading: false,
displayName: '',
title: '',
dataSource: ds.cloneWithRows([{
title: '',
author: ''
}])
})
},
componentDidMount() {
let user = firebaseApp.auth().currentUser;
if (!user.displayName) {
this.props.navigator.push({
name: 'chooseName'
})
} else {
// proceed normally with application
this.setState({
displayName: user.displayName
})
this.listenForItems(topicsRef);
}
},
listenForItems(ref) {
ref.on('value', (snap) => {
let topics = [];
snap.forEach(topic => {
topics.push({
title: topic.val().title,
author: topic.val().author,
key: topic.key
})
})
this.setState({dataSource: ds.cloneWithRows(topics)});
})
},
signOut() {
// sign out the user
firebaseApp.auth().signOut()
.then(() => {
// Sign out successful
this.props.navigator.popToTop();
}, (error) => {
console.log(error);
})
},
details(data) {
this.props.navigator.push({
name: 'topicDetail',
displayName: this.state.displayName,
title: data.title,
author: data.author,
row_uid: data.key
})
},
renderRow(rowData) {
return (
<TouchableOpacity style={styles.row}
onPress={() => this.details(rowData)}
>
<Text style={styles.rowTitle}>
{rowData.title}
</Text>
<Text>
{rowData.author}
</Text>
</TouchableOpacity>
)
},
addTopic() {
topicsRef.push({
title: this.state.title,
author: this.state.displayName
})
},
render() {
if (this.state.loading) {
return (
<Container style={styles.containerSignIn}>
<Content>
<Spinner />
</Content>
</Container>);
}
return (
<View style={styles.flexContainer}>
<View style={styles.header}>
<TouchableOpacity
onPress={() => this.signOut()}
>
<Text style={styles.link}>
Sign out
</Text>
</TouchableOpacity>
<Text style={styles.title}>
{this.state.displayName}
</Text>
</View>
<View style={styles.body}>
<TextInput
placeholder='Something on your mind?'
style={styles.input}
onChangeText={(text) => this.setState({title: text})}
onEndEditing={() => this.addTopic()}
/>
<ListView
style={styles.list}
enableEmptySections={true}
dataSource={this.state.dataSource}
renderRow={(rowData) => this.renderRow(rowData)}
/>
</View>
</View>
)
}
});

I assume your Spinner component works.
Due to possible issues in your react lifecycle what I can recommend in the first run:
1.) if you want your Spinner to be active when your View shows up, set state.loading to true when defining your initialState.
getInitialState() {
return({
loading: true,
...
})
}
2.) change the loading state in the (success) Promise callback of your firebase request and NOT in componentDidMount().
listenForItems(ref) {
ref.on('value', (snap) => {
...
this.setState({
loading: false,
dataSource: ds.cloneWithRows(topics)
});
})
}
Hope that helps.

Related

How to render lists using React Native and Firestore

I'm doing Expo React Native Application using Firestore Database. I'm following the below Tutorial.
Tutorial
function ViewServices () {
const navigation =useNavigation();
const [FullData, setFullData] = useState([]);
const [driverData, setDriverData] = useState([]);
// Retrieving Data
useEffect(() => {
firebase.firestore().collection('driver')
.get()
.then(snapshot => {
if (snapshot.empty) {
console.log('Empty');
return;
}
snapshot.forEach(doc => {
driverData.push(
{
id: doc.id,
});
});
{
driverData? driverData.map((point) => (
firebase.firestore().collection('driver')
.doc(point.id)
.collection('personal')
.get()
.then(snapshot => {
if (snapshot.empty) {
alert('Nothing To Show');
return;
}
snapshot.forEach(doc => {
FullData.push(
{
id : doc.id,
name: (doc.data().firstname),
school: (doc.data().lastname),
});
});
setFullData(FullData);
})
.catch(err => {
console.log('Error getting documents', err);
})
))
: null}
})
.catch(err => {
console.log('Error getting documents', err);
});
}, []);
return(
<FlatList
data={FullData}
renderItem={({ item }) => (
<View style={{ height: 50, flex: 1, alignItems: 'center',
justifyContent: 'center' }}>
<Text>User ID: {item.id}</Text>
<Text>User Name: {item.name}</Text>
</View>
)}
/>
)}
However the data are retrieved fine. But the lists are only shown when I manually press Refresh (Ctrl+S)
How can I retrieve the lists when the screen loads? Please let me know.
I found a solution.
The problem happened because the components are firstly rendered before the data fetching. That's why it required manual refresh.
I have added Activity Indicator component and it will be loaded until the data fetched. After the data successfully fetched, activity indicator will be replaced with flat list component.
function ViewServices () {
**const [loading, setLoading] = useState(true)**
const navigation =useNavigation();
const [FullData, setFullData] = useState([]);
const [driverData, setDriverData] = useState([]);
// Retrieving Data
useEffect(() => {
firebase.firestore().collection('driver')
.get()
.then(snapshot => {
if (snapshot.empty) {
console.log('Empty');
return;
}
snapshot.forEach(doc => {
driverData.push(
{
id: doc.id,
});
});
{
driverData? driverData.map((point) => (
firebase.firestore().collection('driver')
.doc(point.id)
.collection('personal')
.get()
.then(snapshot => {
if (snapshot.empty) {
alert('Nothing To Show');
return;
}
snapshot.forEach(doc => {
FullData.push(
{
id : doc.id,
name: (doc.data().firstname),
school: (doc.data().lastname),
});
});
setFullData(FullData);
**setLoading(false);**
})
.catch(err => {
console.log('Error getting documents', err);
})
))
: null}
})
.catch(err => {
console.log('Error getting documents', err);
});
}, []);
**if (loading) {
return (
<ActivityIndicator size="large" color="#00ff00" justifyContent= "center"/>
)
}**
else{
return(
<FlatList
data={FullData}
renderItem={({ item }) => (
<View style={{ height: 50, flex: 1, alignItems: 'center',
justifyContent: 'center' }}>
<Text>User ID: {item.id}</Text>
<Text>User Name: {item.name}</Text>
</View>
)}
/>
)
}
}

React Native. How to show screens according to the User Authentication status

I'm developing my first ever React Native App. I have created Login/SignUp screen and connect these with Firebase for Authentication. As well as i have some screen containing Drawers. I want that if the user is Not Authenticated. Login/Signup screen should show otherwise HomeScreen(having many drawers) will show. For this i did some checks in MainRouteComponent but its not working
I am uploading my Code of all the related Components as well as some redux code i have used here. I know it will take time to go through that much code but i tried a lot and i am struggling now. Hope many of you will help. :)
Here is my code:-
App.js
import React from 'react';
import Main from './components/MainComponent';
import MainRoute from './components/MainRouteComponent'
import { Provider } from 'react-redux';
import { ConfigureStore } from './redux/configureStore';
import { PersistGate } from 'redux-persist/es/integration/react'
import { Loading } from './components/LoadingComponent';
const { persistor, store } = ConfigureStore();
export default App = () =>{
return (
<Provider store={store}>
<PersistGate
loading={<Loading />}
persistor={persistor}>
<MainRoute/>
</PersistGate>
</Provider>
);
}
MainRouteComponent.js
import React, { useState } from 'react';
import Main from './MainComponent';
import Root from './RootComponent';
import { auth } from '../firebase/firebase';
const AuthContext = React.createContext();
const MainRoute = () => {
const user = auth.currentUser
console.log("User", user)
console.log("Auth", isAuth)
return(
{(user == null) ?
<Root />
:
<Main />
}
)
}
export default MainRoute;
RootComponent.js
import React, {Component} from 'react';
import { createStackNavigator } from 'react-navigation';
import * as Animatable from 'react-native-animatable';
import SplashScreen from './SplashScreen';
import Login from './LoginComponent';
import Register from './RegistrationComponent';
const RootStack = createStackNavigator({
SplashScreen: { screen: SplashScreen,
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: "#512DA8"
},
headerTitle: "Welcome Foodies",
headerTintColor: '#fff',
headerTitleStyle: {
color: "#fff",
alignItems: 'center'
}
})
},
LoginComponent: {
screen: Login,
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: "#512DA8"
},
headerTitle: "Login",
headerTintColor: '#fff',
headerTitleStyle: {
color: "#fff",
alignItems: 'center'
}
})
},
Register: {
screen: Register,
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: "#512DA8"
},
headerTitle: "Sign Up",
headerTintColor: '#fff',
headerTitleStyle: {
color: "#fff",
alignItems: 'center'
}
})
},
},
{
initialRouteName: 'SplashScreen',
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: "#512DA8"
},
headerTintColor: '#fff',
headerTitleStyle: {
color: "#fff"
}
})
}
);
class Root extends Component {
render() {
return (
<RootStack />
)
}
}
export default Root;
LoginComponent.js
import React, { Component } from 'react';
import { View, StyleSheet, Text, ScrollView, Image } from 'react-native';
import { Input, CheckBox, Button, Icon } from 'react-native-elements';
import * as SecureStore from 'expo-secure-store';
import { loginUser} from '../redux/ActionCreators';
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
auth: state.AUTH
}
}
const mapDispatchToProps = dispatch => {
return {
loginUser: (creds) => dispatch(loginUser(creds))
}
}
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
remember: false
}
}
componentDidMount() {
SecureStore.getItemAsync('userinfo')
.then((userdata) => {
let userinfo = JSON.parse(userdata);
if (userinfo) {
this.setState({email: userinfo.email});
this.setState({password: userinfo.password});
this.setState({remember: true})
}
})
}
static navigationOptions = {
title: 'Login',
tabBarIcon: ({ tintColor }) => (
<Icon
name='sign-in'
type='font-awesome'
size={24}
iconStyle={{ color: tintColor }}
/>
)
};
handleLogin() {
this.props.loginUser({email: this.state.email, password: this.state.password});
//event.preventDefault();
if (this.state.remember)
SecureStore.setItemAsync('userinfo', JSON.stringify({email: this.state.email, password: this.state.password}))
.catch((error) => console.log('Could not save user info', error));
else
SecureStore.deleteItemAsync('userinfo')
.catch((error) => console.log('Could not delete user info', error));
this.setState({
email: '',
password: '',
remember: false
})
this.props.navigation.navigate('Home')
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Input
placeholder="Email"
leftIcon={{ type: 'font-awesome', name: 'envelope-o' }}
onChangeText={(email) => this.setState({email})}
value={this.state.email}
containerStyle={styles.formInput}
/>
<Input
placeholder="Password"
leftIcon={{ type: 'font-awesome', name: 'key' }}
onChangeText={(password) => this.setState({password})}
value={this.state.password}
containerStyle={styles.formInput}
/>
<CheckBox title="Remember Me"
center
checked={this.state.remember}
onPress={() => this.setState({remember: !this.state.remember})}
containerStyle={styles.formCheckbox}
/>
<View style={styles.formButton}>
<Button
onPress={() => this.handleLogin()}
title="Login"
icon={
<Icon
name='sign-in'
type='font-awesome'
size={24}
color= 'white'
/>
}
buttonStyle={{
backgroundColor: "#512DA8"
}}
/>
</View>
<View style={styles.formButton}>
<Button
onPress={() => navigate('Register')}
title="Register"
clear
icon={
<Icon
name='user-plus'
type='font-awesome'
size={24}
color= 'blue'
/>
}
titleStyle={{
color: "blue"
}}
buttonStyle={{
backgroundColor: "transparent"
}}
/>
</View>
</View>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
ActionCreator.js
import * as ActionTypes from './ActionTypes';
import { auth, firestore, fireauth, firebasestore } from '../firebase/firebase';
export const requestLogin = () => {
return {
type: ActionTypes.LOGIN_REQUEST
}
}
export const receiveLogin = (user) => {
return {
type: ActionTypes.LOGIN_SUCCESS,
user
}
}
export const loginError = (message) => {
return {
type: ActionTypes.LOGIN_FAILURE,
message
}
}
export const loginUser = (creds) => (dispatch) => {
// We dispatch requestLogin to kickoff the call to the API
dispatch(requestLogin(creds))
return auth.signInWithEmailAndPassword(creds.email, creds.password)
.then(() => {
var user = auth.currentUser;
dispatch(fetchFavorites());
dispatch(receiveLogin(user));
})
.then(response => { console.log('Login Successful', response); alert('Thank you for login!'); })
.catch(error => {console.log('Error', error); alert(error)})
.catch(error => dispatch(loginError(error.message)))
};
I also have Login Reducer as auth.js as i thought this can help in checking authentication to show screen accordingly.
auth.js
import * as ActionTypes from './ActionTypes';
export const Auth = (state = {
isLoading: false,
isAuthenticated: false,
user: null,
errMess: null
}, action) => {
switch (action.type) {
case ActionTypes.LOGIN_REQUEST:
return {...state,
isLoading: true,
isAuthenticated: false,
};
case ActionTypes.LOGIN_SUCCESS:
return {...state,
isLoading: false,
isAuthenticated: true,
errMess: '',
user: action.user
};
case ActionTypes.LOGIN_FAILURE:
return {...state,
isLoading: false,
isAuthenticated: false,
errMess: action.message
};
case ActionTypes.LOGOUT_REQUEST:
return {...state,
isLoading: true,
isAuthenticated: true
};
case ActionTypes.LOGOUT_SUCCESS:
return {...state,
isLoading: false,
isAuthenticated: false,
token: '',
user: null
};
default:
return state
}
}
Make separate routing for the stack screens which you don't want to be shown ! Try to make 2 stacks!

getting lat/long coordinates from firebase/firestore collection

im relative new to react native and firebase and it would be awesome if anyone could help me with this problem. currently when im adding new posts to my firebase collection i display all post with a flatlist and it works fine. but is it possible to get only the currentLatitude and currentLongitude for my markers? my target is to generate a new marker for each post.
Events = []
this.firestore.collection("Events").get().then(snapshot => {
snapshot.forEach(doc => {
Events.push(doc.data())
})
})
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
mapType='hybrid'
showsUserLocation style={{flex: 1}}>
<MapView.Marker
coordinate={{latitude: //currentLatitude,
longitude: //currntLongitude}}
title={("Test")}
description={("Test")}
/>
</MapView>
</View>
</SafeAreaView>
);
}
}
#DevAS thanks for your patience.. this was made from 3 different .js files.. but I don't now how to get it just into the map.js.
The final result should look something like this:
enter image description here
Everything except for the lat/lng cords are supposed to be in the callout-window.
Item.js:
import { Ionicons } from '#expo/vector-icons';
import React from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import Fire from '../screens/Fire'
const profileImageSize = 36;
const padding = 12;
export default class Item extends React.Component {
state = {
user: {}
};
componentDidMount() {
const user = this.props.uid || Fire.shared.uid;
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
if (!this.props.imageWidth) {
// Get the size of the web image
Image.getSize(this.props.image, (width, height) => {
this.setState({ width, height });
});
}
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { title, address, name, imageWidth, imageHeight, image, currentLatitude, currentLongitude } = this.props;
// Reduce the name to something
const imgW = imageWidth || this.state.width;
const imgH = imageHeight || this.state.height;
const aspect = imgW / imgH || 1;
return (
<View>
<Header image={{ uri: this.state.user.avatar }} name={this.state.user.name} />
<Image
resizeMode="contain"
style={{
backgroundColor: "#D8D8D8",
width: "100%",
aspectRatio: aspect
}}
source={{ uri: image }}
/>
<Metadata
name={this.state.user.name}
address={address}
title={title}
currentLongitude={currentLongitude}
currentLatitude={currentLatitude}
/>
</View>
);
}
}
const Metadata = ({ name, address, title, currentLongitude, currentLatitude}) => (
<View style={styles.padding}>
<IconBar />
<Text style={styles.text}>{name}</Text>
<Text style={styles.subtitle}>{address}</Text>
<Text style={styles.subtitle}>{title}</Text>
<Text style={styles.subtitle}>Lat: {currentLatitude}</Text>
<Text style={styles.subtitle}>Lng: {currentLongitude}</Text>
</View>
);
const Header = ({ name, image }) => (
<View style={[styles.row, styles.padding]}>
<View style={styles.row}>
<Image style={styles.avatar} source={image} />
<Text style={styles.text}>{name}</Text>
</View>
<Icon name="ios-more" />
</View>
);
const Icon = ({ name }) => (
<Ionicons style={{ marginRight: 8 }} name={name} size={26} color="black" />
);
const IconBar = () => (
<View style={styles.row}>
<View style={styles.row}>
<Icon name="ios-heart-empty" />
<Icon name="ios-chatbubbles" />
<Icon name="ios-send"/>
</View>
<Icon name="ios-bookmark" />
</View>
);
const styles = StyleSheet.create({
text: { fontWeight: "600" },
subtitle: {
opacity: 0.8
},
row: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
},
padding: {
padding
},
avatar: {
aspectRatio: 1,
backgroundColor: "#D8D8D8",
borderWidth: StyleSheet.hairlineWidth,
borderColor: "#979797",
borderRadius: profileImageSize / 2,
width: profileImageSize,
height: profileImageSize,
resizeMode: "cover",
marginRight: padding
}
});
List.js
import React from 'react';
import { FlatList } from 'react-native';
import Footer from './Footer';
import Item from './Item';
class List extends React.Component {
renderItem = ({ item }) => <Item {...item} />;
keyExtractor = item => item.key;
render() {
const { onPressFooter, ...props } = this.props;
return (
<FlatList
keyExtractor={this.keyExtractor}
ListFooterComponent={footerProps => (
<Footer {...footerProps} onPress={onPressFooter} />
)}
renderItem={this.renderItem}
{...props}
/>
);
}
}
export default List;
FeedScreen.js
import firebase from "firebase";
import React, { Component } from "react";
import { LayoutAnimation, RefreshControl } from "react-native";
import List from "../components/List";
import Fire from "./Fire";
// Set the default number of images to load for each pagination.
const PAGE_SIZE = 5;
console.disableYellowBox = true;
export default class FeedScreen extends Component {
state = {
loading: false,
data: {}
};
componentDidMount() {
// Check if we are signed in...
if (Fire.shared.uid) {
// If we are, then we can get the first 5 posts
this.makeRemoteRequest();
} else {
// If we aren't then we should just start observing changes. This will be called when the user signs in
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.makeRemoteRequest();
}
});
}
}
// Append the item to our states `data` prop
addPosts = posts => {
this.setState(previousState => {
let data = {
...previousState.data,
...posts
};
return {
data,
// Sort the data by timestamp
posts: Object.values(data).sort((a, b) => a.timestamp < b.timestamp)
};
});
};
// Call our database and ask for a subset of the user posts
makeRemoteRequest = async lastKey => {
// If we are currently getting posts, then bail out..
if (this.state.loading) {
return;
}
this.setState({ loading: true });
// The data prop will be an array of posts, the cursor will be used for pagination.
const { data, cursor } = await Fire.shared.getPaged({
size: PAGE_SIZE,
start: lastKey
});
this.lastKnownKey = cursor;
// Iteratively add posts
let posts = {};
for (let child of data) {
posts[child.key] = child;
}
this.addPosts(posts);
// Finish loading, this will stop the refreshing animation.
this.setState({ loading: false });
};
// Because we want to get the most recent items, don't pass the cursor back.
// This will make the data base pull the most recent items.
_onRefresh = () => this.makeRemoteRequest();
// If we press the "Load More..." footer then get the next page of posts
onPressFooter = () => this.makeRemoteRequest(this.lastKnownKey);
render() {
// Let's make everything purrty by calling this method which animates layout changes.
LayoutAnimation.easeInEaseOut();
return (
<List
refreshControl={
<RefreshControl
refreshing={this.state.loading}
onRefresh={this._onRefresh}
/>
}
onPressFooter={this.onPressFooter}
data={this.state.posts}
/>
);
}
}

Register and push data to Firebase in React Native

I have a registers and push data to Firebase function. I have a problem that when two functions are nested they are registered and stored in Firebase but there are warnings (below). But when I delete the push data function, there is no warning. I want to be able to register and be able to save data. Or can I write two separate functions and when onPress can call two functions at the same time?
This is my code:
handleSignUp = () => {
const { username, email, passwordOne } = this.state;
const { history } = this.props;
auth.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
// Create a user in your own accessible Firebase Database too
db.doCreateUser(authUser.user.uid, username, email)
.then(() => {
this.setState({ ...INITIAL_STATE }, () => {
history.navigation.navigate("MainScreenNavigator");
});
})
.catch(error => this.setState({ errorMessage: error.message }));
})
.catch(error => this.setState({ errorMessage: error.message }));
};
And warning:
Warning: Can't call setState (or forceUpdate) on an unmounted
component. This is a no-op, but it indicates a memory leak in your
application. To fix, cancel all subscriptions and asynchronous tasks
in the componentWillUnmount method.
doCreactUser function
export const doCreateUser = (id, username, email) =>
db.ref(`users/${id}`).set({
username,
email,
});
Full code:
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TextInput,
TouchableOpacity,
KeyboardAvoidingView
} from "react-native";
import Logo from "../components/Logo";
import { Actions } from "react-native-router-flux";
import { auth, db, firebase } from "../firebase/";
const INITIAL_STATE = {
username: "",
email: "",
passwordOne: "",
passwordTwo: "",
errorMessage: null
};
export default class Signup extends Component<{}> {
constructor(props) {
super(props);
this.state = { INITIAL_STATE };
}
handleSignUp = () => {
const { username, email, passwordOne } = this.state;
const { history } = this.props;
auth.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
// Create a user in your own accessible Firebase Database too
db.doCreateUser(authUser.user.uid, username, email)
.then(() => {
this.setState({ ...INITIAL_STATE }, () => {
history.navigation.navigate("MainScreenNavigator");
});
})
.catch(error => this.setState({ errorMessage: error.message }));
})
.catch(error => this.setState({ errorMessage: error.message }));
};
goBack() {
Actions.pop();
}
render() {
const {
username,
email,
passwordOne,
passwordTwo,
} = this.state;
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === "" ||
email === "" ||
username === "";
const display = isInvalid ? "none" : "flex";
return (
<View style={styles.container}>
<StatusBar backgroundColor="#99d066" barStyle="light-content" />
<Logo />
<KeyboardAvoidingView>
<TextInput
style={styles.inputBox}
underlineColorAndroid="rgba(0,0,0,0)"
placeholder="Full Name"
placeholderTextColor="#000"
autoCapitalize="none"
selectionColor="#fff"
keyboardType="default"
onSubmitEditing={() => this.passwordOne.focus()}
onChangeText={username => this.setState({ username })}
value={this.state.username}
/>
<TextInput
style={styles.inputBox}
underlineColorAndroid="rgba(0,0,0,0)"
placeholder="Email"
placeholderTextColor="#000"
autoCapitalize="none"
selectionColor="#fff"
keyboardType="email-address"
onSubmitEditing={() => this.passwordOne.focus()}
onChangeText={email => this.setState({ email })}
value={this.state.email}
/>
<TextInput
style={styles.inputBox}
underlineColorAndroid="rgba(0,0,0,0)"
placeholder="Password"
secureTextEntry={true}
placeholderTextColor="#000"
autoCapitalize="none"
ref={input => (this.passwordOne = input)}
onChangeText={passwordOne => this.setState({ passwordOne })}
value={this.state.passwordOne}
/>
<TextInput
style={styles.inputBox}
underlineColorAndroid="rgba(0,0,0,0)"
placeholder="Confirm Password"
secureTextEntry={true}
placeholderTextColor="#000"
autoCapitalize="none"
ref={input => (this.passwordTwo = input)}
onChangeText={passwordTwo => this.setState({ passwordTwo })}
value={this.state.passwordTwo}
/>
</KeyboardAvoidingView>
<TouchableOpacity style={[styles.button, { display }]}>
<Text style={styles.buttonText} onPress={this.handleSignUp}>
Sign up
</Text>
</TouchableOpacity>
{this.state.errorMessage && (
<Text style={{ color: "#b71c1c", textAlign: "center" }}>
{this.state.errorMessage}
</Text>
)}
<View style={styles.signupTextCont}>
<Text style={styles.signupText}>Already have an account?</Text>
<TouchableOpacity onPress={this.goBack}>
<Text
style={styles.signupButton}
onPress={() => this.props.navigation.navigate("Login")}
>
{" "}
Sign in
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({...});

React Native: Object is not a function

I am working with Firebase authentification in my React Native android app, however every time I try to login and press the button, it gives me this error:
Object is not a function(evaluating 'this2.state'({
error: 'Authentification failed', loading: false
}))
I have looked up similar answers as well, but it doesn't seem to match my problem. Any help would be appreciated.
Here is my code:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PixelRatio,
TouchableOpacity,
Image,
Button,
} from 'react-native';
import * as firebase from 'firebase';
import { FormLabel, FormInput } from 'react-native-elements';
import Help from './app/components/Help';
import { Input } from './app/components/Input';
const util = require('util');
firebase.initializeApp({
apiKey: 'AIzaSyCmjeFuDoMeOkeG5J-TCXzDJ1vtaDqUXjE',
authDomain: 'dev-pre-do.firebaseapp.com',
databaseURL: 'https://dev-pre-do.firebaseio.com',
projectId: 'dev-pre-do',
storageBucket: 'dev-pre-do.appspot.com',
messagingSenderId: '943752089124'
}
);
class LoginScreen extends React.Component {
static navigationOptions ={
header: null,
};
constructor(props) {
super(props);
this.state = {email:'', password:'', error: '', loading:false};
}
onLoginPress(){
this.setState({error:'', loading:true});
const{email, password} = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => {
this.state({error: '', loading: false});
this.props.navigation.navigate('CreateIdeaMenu');
})
.catch(() => {
this.state({error: 'Authentification failed', loading: false});
})
}
renderButtonOrLoading(){
if(this.state.loading) {
return (
<Text style={styles.loading}> Loading </Text>
)}
return (
<View>
<Button style={styles.Button} title='Login'
onPress={this.onLoginPress.bind(this)}></Button>
</View>
)
}
render() {
return (
<View style={styles.container}>
<Help onPress = {()=> navigate("HelpFirst")}/>
<Image style={styles.logo}
source={require('./app/images/PREDO_logo_white.png')}
/>
<FormLabel> Email</FormLabel>
<FormInput onChangeText={email => this.setState({ email })}/>
<FormLabel> Password</FormLabel>
<FormInput onChangeText={password => this.setState({ password })}/>
<Text>{this.state.error}</Text>
{/* <Input
placeholder='Email'
label='Email'
onChangeText={email => this.setState({ email })}
value={this.state.email}
/>
<Input
placeholder='Password'
label='Password'
secureTextEntry
onChangeText={password => this.setState({ password })}
value={this.state.password} */}
{this.renderButtonOrLoading()}
{/* <Button onPress={() => console.log('pressed')}>Log in</Button>*/}
{/* <RegForm onPress = {()=> navigate("CreateIdeaMenu")} /> */}
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex:1,
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#1e1f20',
paddingLeft: 60,
paddingRight: 60,
paddingTop: 10,
},
Button: {
width: 200,
height:100,
marginBottom: 10,
backgroundColor: 'purple',
alignItems: 'center',
justifyContent: 'center',
},
logo: {
width: 360,
height:94,
marginBottom: 80,
marginTop: 20,
},
loading: {
color: 'white',
fontSize: 50,
}
});
export default LoginScreen;
Update your code as below:
onLoginPress(){
this.setState({error:'', loading:true});
const{email, password} = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => {
this.setState({error: '', loading: false});
this.props.navigation.navigate('CreateIdeaMenu');
})
.catch(() => {
this.setState({error: 'Authentification failed', loading: false});
})
}

Resources