Reactnative Issue - api

I have a very simple login screen where the user enters userid and password. when the user clicks on login button then flow moves to next screen if entered userid/password combination is correct.
on click of login button, I am calling an API with userid and password as input. API returns a count of matching records from DB in JSON format.If the count is >0 then login is successful.
Issue: I have to click login button twice. when I click on login button nothing happens but if I click it again then I get fail message or move to the second screen depending on userid/password combination. I am copying my code below. I'll appreciate any help.
import React, { Component } from 'react';
import {
AppRegistry,
View,
Image,
StyleSheet,
KeyboardAvoidingView,
TextInput,
TouchableOpacity,
Text,
StatusBar,
Alert
} from 'react-native';
import {
StackNavigator
} from 'react-navigation';
export default class Login extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: '',
uCount: -1,
data: []
};
}
getData(){
var url="https://myurl/verifySubscription.php?email=" + this.state.email + "&password=" + this.state.password;
console.log("URL:", url);
return fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
uCount: responseJson.count
})
})
.catch((error) => {
console.error(error);
});
}
async _onPressButton() {
await this.getData();
console.log("uCount:", this.state.uCount);
if (this.state.uCount < 1) {
Alert.alert('Login Failed: Incorrect email or password')
} else {
this.props.navigation.navigate('LoginSuccess', { email: this.state.email, password: this.state.password})
}
}
render() {
return (
<KeyboardAvoidingView behavior="padding" style={styles.wrapper}>
<View style={styles.topView}>
<Image style={styles.imageStyle}
source={require('../images/main.jpg')}
/>
</View>
<View style={styles.bottomView}>
<StatusBar
barStyle="light-content"
/>
<TextInput style={styles.Input}
placeholder="Email"
placeholderTextColor="rgba(255,255,255,0.7)"
keyBoardType='email-address'
returnKeyType="next"
autoCapitalize="none"
autoCorrect={false}
onSubmitEditing={() => this.passwordInput.focus()}
onChangeText={(text) => this.setState({email:text})}
/>
<TextInput style={styles.Input}
placeholder="Password"
placeholderTextColor="rgba(255,255,255,0.7)"
returnKeyType="go"
secureTextEntry
autoCapitalize="none"
autoCorrect={false}
ref={(next) => this.passwordInput = next}
onChangeText={(text) => this.setState({password:text})}
/>
<TouchableOpacity style={styles.button1Container} onPress={ this._onPressButton.bind(this) }>
<Text style={styles.buttonText}>
Login
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button2Container}>
<Text style={styles.buttonText}>
Sign up
</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
wrapper: {
backgroundColor: '#4A7AA5',
flex: 1
},
topView: {
flexGrow: 1
},
imageStyle: {
width: null,
flex: 1
},
bottomView: {
padding: 20
},
Input: {
height:40,
backgroundColor: 'rgba(255,255,255,0.3)',
marginBottom: 10,
color: '#FFF',
paddingHorizontal: 10
},
button1Container: {
backgroundColor: 'rgba(200,200,255,0.3)',
padding: 10
},
buttonText: {
textAlign: 'center',
color: '#FFF',
fontWeight: '700'
},
button2Container: {
padding: 10
}
});

Issue maybe related to the async process when you press the button. fetch will return a promise which then can be resolve after response is completed. Try this, not using await (es2017), just es6.
getData(){
var url="https://myurl/verifySubscription.php?email=" + this.state.email +
"&password=" + this.state.password;
console.log("URL:", url);
return fetch(url);
}
_onPressButton() {
this.getData().then((response) => response.json())
.then((responseJson) => {
const cnt = responseJson.cnt;
if (cnt < 1) {
Alert.alert('Login Failed: Incorrect email or password')
} else {
this.props.navigation.navigate('LoginSuccess', { email:
this.state.email, password: this.state.password})
}
});
}

Related

How can I write well formatted code in React Native?

I'm new in React Native. I want to write well formatted code so I can manage big apps easily and I can change existing code with new change.
Right now I'm putting all component in single block, so I'm confused when I want to change in that.
I have made registration screen as below. My code messed up and looks so distorted. Please help me how can I manage my code to good fragments way.
import LoginScreen from './Login';
import React, {Component} from 'react';
import 'react-native-gesture-handler';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
TextInput,
Button,
Image,
KeyboardAvoidingView,
} from 'react-native';
class RegistrationScreen extends Component {
state = {
textInputTexts: {
username: '',
password: '',
email: '',
phoneno: '',
},
validFlags: {
username: false,
password: false,
email: false,
phoneno: false,
},
};
validateEmail = text => {
console.log(text);
let reg = /^([\w.%+-]+)#([\w-]+\.)+([\w]{2,})$/i;
console.log(reg.test(text));
if (reg.test(text) === false) {
console.log('Email is Not Correct');
return false;
} else {
console.log('Email is Correct');
return true;
}
};
validatePassword = text => {
console.log(text);
var passRegex = new RegExp(
'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##$%^&*])(?=.{8,})',
);
console.log(passRegex.test(text));
if (passRegex.test(text) === false) {
console.log('Password is Not Valid');
return false;
} else {
console.log('Password is Correct');
return true;
}
};
validateUsername = text => {
console.log(text);
var usernameRegex = new RegExp('(?=.*[a-fA-F])(?=.{5,})');
console.log(usernameRegex.test(text));
if (usernameRegex.test(text) === false) {
console.log('Username is Not Valid');
return false;
} else {
console.log('Username is Correct');
return true;
}
};
textInputTextChanged = (key, value) => {
var valid = false;
if (key === 'username') {
valid = this.validateUsername(value);
} else if (key === 'password') {
valid = this.validatePassword(value);
} else if (key === 'email') {
valid = this.validateEmail(value);
} else if (key === 'phoneno') {
if (value.length === 10) {
valid = true;
}
}
if (valid) {
console.log('Input is valid');
} else {
console.log('Input is not valid');
}
//this.setState(Object.assign(this.state.textInputTexts, {[key]: value}));
this.setState({
textInputTexts: {...this.state.textInputTexts, [key]: value},
validFlags: {...this.state.validFlags, [key]: valid},
});
//console.log(this.state);
};
signUp = () => {
const {validFlags} = this.state;
console.log('Sign up click');
if (
validFlags.username &&
validFlags.password &&
validFlags.email &&
validFlags.phoneno
) {
// navigate to Login screen
console.log('Go to login screen');
this.props.navigation.navigate('LoginScreen');
}
};
render() {
const {validFlags} = this.state; // this is for constant parameter of this.state to avoid writing this.state.validFlags
console.log(this.state);
const errorImage = (
<Image
source={require('./../images/error-icon.png')}
style={styles.errorImageStyle}
/>
);
return (
<SafeAreaView>
<ScrollView>
<View>
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
placeholder="Username"
autoCapitalize="none"
placeholderTextColor="#a7a7a7"
onChangeText={value =>
this.textInputTextChanged('username', value)
}
/>
{!validFlags.username && errorImage}
</View>
{!validFlags.username && (
<Text style={styles.errorLabelStyle}>
Username must contain 5 alphabets
</Text>
)}
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
placeholder="Password"
autoCapitalize="none"
placeholderTextColor="#a7a7a7"
secureTextEntry={true}
onChangeText={value =>
this.textInputTextChanged('password', value)
}
/>
{!validFlags.password && errorImage}
</View>
{!validFlags.password && (
<Text style={styles.errorLabelStyle}>
Password must contain 8 characters with atleast one special
character, Capital and small characters and numbers
</Text>
)}
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
placeholder="Email Id"
autoCapitalize="none"
placeholderTextColor="#a7a7a7"
onChangeText={value =>
this.textInputTextChanged('email', value)
}
/>
{!validFlags.email && errorImage}
</View>
{!validFlags.email && (
<Text style={styles.errorLabelStyle}>
Email text should be valid email id
</Text>
)}
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
placeholder="Phone No."
autoCapitalize="none"
placeholderTextColor="#a7a7a7"
keyboardType="number-pad"
onChangeText={value =>
this.textInputTextChanged('phoneno', value)
}
/>
{!validFlags.phoneno && errorImage}
</View>
{!validFlags.phoneno && (
<Text style={styles.errorLabelStyle}>
Phone number must contain 10 digits
</Text>
)}
<Button title="Sign Up" onPress={this.signUp} />
</View>
</ScrollView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
width: 300,
paddingTop: 300,
},
textInput: {
flex: 1,
height: 50,
backgroundColor: '#E2E2E2',
marginTop: 10,
marginRight: 10,
padding: 8,
color: 'black',
borderRadius: 10,
fontSize: 16,
fontWeight: '500',
},
textInputContainer: {
flexDirection: 'row',
alignItems: 'center',
},
errorImageStyle: {
width: 20,
height: 20,
},
errorLabelStyle: {
alignSelf: 'flex-start',
color: 'red',
paddingLeft: 8,
marginBottom: 10,
fontSize: 12,
},
});
const AppNavigator = createStackNavigator(
{
RegistrationScreen: {
screen: RegistrationScreen,
},
LoginScreen: {
screen: LoginScreen,
},
},
{
initialRouteName: 'LoginScreen',
defaultNavigationOptions: {
title: 'App',
},
},
);
export default createAppContainer(AppNavigator);
Best advantages of using react-native is its component driven. You can follow the some of the below mentioned things,
Have separate file for navigation, I see createStackNavigator and other things in registration page, its not good, it must be put in different file.
Separate out styles in different file, each component must have a corresponding style file from where it refers too.
Write as much re-usable components as possible, for ex in your case,
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
placeholder="Email Id"
autoCapitalize="none"
placeholderTextColor="#a7a7a7"
onChangeText={value =>
this.textInputTextChanged('email', value)
}
/>
{!validFlags.email && errorImage}
</View>
Is repeated a lot of times, make it as a separate component and pass only the required props to it, let the common things remain as it is.
For whole application architecture point of view use redux
Use Prettier for code formatting.

Redirecting user based on his authentication

In my react native application, I want to check if a user has already logged in before, then he must be redirected to 'Home' directly without asking him for credentials again. The 'Home' component consists of logout button in a sidebar.
My current code works fine for new user logging, but I am stuck on how to check if again the user open the application, his login token should persist and he must be redirected to 'Home' directly.
Here is my code:
import React, { Component } from 'react'
import { Text, View, Image, TextInput, TouchableOpacity, ScrollView, AsyncStorage, ToastAndroid } from 'react-native'
import axios from 'axios';
export default class Login extends Component {
constructor(){
super();
this.state = {
username: '',
password: '',
isLoggedIn: false,
loginChecked: false,
}
}
componentDidMount(){
this.getItem('userID');
}
//function to extract storage token. Any name can be given ot it.
async getItem(item){
console.log('method ran login screen');
console.log(this.state.isLoggedIn)
try{
const value = await AsyncStorage.getItem(item);
if(value !== null){
this.setState({
isLoggedIn: true,
loginChecked: true
})
}
else{
this.setState({
isLoggedIn: false,
loginChecked: true
})
}
}
catch(error){
console.log(error)
}
console.log(this.state.isLoggedIn)
}
//function to remove storage token
async removeItem(item){
try{
const value = await AsyncStorage.removeItem(item);
if(value == null){
this.setState({
isLoggedIn: false
})
}
}
catch(error){
//handle errors here
}
}
userLogin = () => {
if(this.state.username != '' && this.state.password != ''){
axios.post('http://bi.servassure.net/api/login', {
username: this.state.username,
password: this.state.password
})
.then(res => {
let userToken = res.data.token;
console.log(res.data);
if(res.data.success){
AsyncStorage.setItem('userID', userToken);
this.setState({
isLoggedIn: true
})
this.props.navigation.navigate('Home');
}
else{
ToastAndroid.showWithGravity(
'Invalid login' ,
ToastAndroid.SHORT,
ToastAndroid.CENTER
);
}
})
.catch(err => {
console.log(err);
});
}
else{
ToastAndroid.showWithGravity(
'Please Enter Credentials' ,
ToastAndroid.SHORT,
ToastAndroid.CENTER
);
}
}
logOut(){
this.removeItem('userID');
}
render() {
return (
<ScrollView>
<View style={{justifyContent:'center', alignItems:'center'}}>
<View style={{marginVertical:20}}>
<Text>
Login to your account
</Text>
</View>
<View>
<TextInput
style={{width: 300, height: 50, borderColor: 'gray', borderWidth: 1, borderRadius: 10, marginVertical: 10}}
onChangeText={(username) => this.setState({username})}
placeholder='username'
autoCapitalize = 'none'
/>
<TextInput
style={{width: 300, height: 50, borderColor: 'gray', borderWidth: 1, borderRadius: 10}}
onChangeText={(password) => this.setState({password})}
placeholder='password'
secureTextEntry={true}
/>
</View>
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<TouchableOpacity
style={{width: 300, height: 50, borderWidth:1, borderRadius: 50, borderColor: 'gray', justifyContent: 'center', alignItems: 'center', marginVertical: 10}}
onPress={this.userLogin}>
<Text>
LOGIN
</Text>
</TouchableOpacity>
<Text>Forget Password</Text>
</View>
</View>
</ScrollView>
)
}
}
Also, I have a SplashScreen before login:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class SplashScreen extends Component {
componentDidMount(){
setTimeout( () => {
this.props.navigation.navigate('Login')
}, 2000)
}
render() {
return (
<View style={styles.viewStyles}>
<Text style={styles.textStyles}> My App </Text>
</View>
)
}
}
const styles = {
viewStyles: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'orange'
},
textStyles: {
color: 'white',
fontSize: 40,
fontWeight: 'bold'
}
}
I am bit new to react native, please help to figure this out.
Do something like this in your Login.js file:
import {AsyncStorage} from react-native;
After getting the response success of login API you can do this:
AsyncStorage.setItem('userID', responsejson.user_detail.userID);
in the same way, you can store the token also
AsyncStorage.setItem('token', responsejson.user_detail.token);
Then in your splashscreen.js, import AsyncStorage the same way as above and then place this code in componentWillMount() or componentDidMount()
of your splashscreen.js
var value = AsyncStorage.getItem('token');
value.then((e)=>{
if (e == '' || e == null ){
this.props.navigation.replace('Login')
}else {
this.props.navigation.replace('Home')
}
})
Explanation: When splashscreen.js is loaded then it checks for the token in asyncstorage and if it gets the token navigate to Home screen else navigate to Login screen.
Import the React Navigation library and use the Switch Navigator. It was designed to handle app navigation based on the login status of the user.
This article explains everything with examples

Showing loading animation when clicking login button not working

I have the following code. I have two issues. First one, When I click the login button is shows the loading animation. But, it should toggle if the login process is success or fail. It's not working. Second one, If I do not add this line of code "this.toggleLoader = this.toggleLoader.bind(this);", the toggleLoader function show the error, this.setState is not a function. Please not that after log in successfully, the page navigate to new screen Home page. How can I toggle the loader before that ? If I call the function toggleLoader() after the if loop, not working.
import React, {Component} from 'react'
import {
Alert,
AsyncStorage,
Keyboard,
Text,
View,
TextInput,
TouchableHighlight, TouchableOpacity,
Image,
ActivityIndicator,
} from 'react-native'
import config from "../../../../config";
import styles from './style'
import {Icon} from "react-native-elements";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
credentials: {
email: "",
password: "",
},
loading: false,
};
this.toggleLoader = this.toggleLoader.bind(this);
}
updateText(text, field) {
let newCredentials = Object.assign(this.state.credentials);
newCredentials[field] = text;
this.setState = ({
credentials: newCredentials
})
}
toggleLoader() {
this.setState({
loading: !this.state.loading
});
}
async login() {
Keyboard.dismiss();
let credentials = this.state.credentials;
if (this.state.credentials.email == '' || this.state.credentials.password == '') {
Alert.alert("Please fill all the fields.");
} else {
const that = this;
credentials.email = that.state.credentials.email.toLowerCase();
// start loading when all fields are fill
this.setState({ loading: !this.state.loading });
fetch(config.baseURL + 'mobileapi/get_token/?username=' + `${that.state.credentials.email}` + '&password=' + `${that.state.credentials.password}`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
credentials: credentials,
}),
})
.then((response) => response.json())
.then(responseJson => {
//stop loading after successful response
this.setState({ loading: !this.state.loading });
if (responseJson.confirmation === "success") {
// alert(JSON.stringify(responseJson.data));
AsyncStorage.setItem('USER_ID', responseJson.data.user_id);
AsyncStorage.setItem('USER_NAME', responseJson.data.user_name);
AsyncStorage.setItem('USER_TYPE', responseJson.data.user_type);
AsyncStorage.setItem('FIRST_NAME', responseJson.data.first_name);
AsyncStorage.setItem('LAST_NAME', responseJson.data.last_name);
AsyncStorage.setItem('EMAIL', responseJson.data.user_email);
AsyncStorage.setItem('AUTHENTICATION_TOKEN', responseJson.data.token);
setTimeout(() => {
this.props.navigation.navigate("Home")
}, 500);
} else {
setTimeout(() => {
//code to handle an error
throw new Error(responseJson.message);
}, 500);
}
})
.catch((err) => {
//stop loading
this.setState({ loading: !this.state.loading });
setTimeout(() => {
if (JSON.stringify(err.message) === JSON.stringify('Network request failed')) {
alert('Please check your internet connection or try again later');
} else {
alert(JSON.stringify(err.message));
}
}, 500);
})
}
}
render() {
const loginText = (this.state.loader) ? 'Loading' : 'Login';
return (
<View style={styles.container}>
<Image source={require('../../../../assets/images/icons/logo.png')}
style={{width: 99, height: 99, margin: 5,}}/>
<Text style={{fontSize: 20, margin: 20, color: "#0aa1e2"}}>Test App</Text>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/username.png')}/>
<TextInput style={styles.inputs}
placeholder="Username"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'email')
}} value={this.state.email}
autoCorrect={false}
autoCapitalize={"none"}
/>
</View>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/password.png')}/>
<TextInput style={styles.inputs}
placeholder="Password"
secureTextEntry={true}
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'password')
}}
value={this.state.password}
autoCorrect={false}
secureTextEntry/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]}
onPress={this.login.bind(this)} >
<View style={{justifyContent: 'center', flex: 1, flexDirection: 'row'}}>
{this.state.loading === false ?
<Icon name='login' type='entypo' size={16} color='white'/> :
<ActivityIndicator size="small" color="#ffffff"/>}
<Text style={styles.loginText}> {loginText} </Text>
</View>
</TouchableHighlight>
</View>
);
}
}
export default Login;
I have updated your login() method. Please try it. It may help you.
async login() {
Keyboard.dismiss();
let credentials = this.state.credentials;
if (this.state.credentials.email == '' || this.state.credentials.password == '') {
Alert.alert("Please fill all the fields.");
} else {
credentials.email = that.state.credentials.email.toLowerCase();
// start loading when all fields are fill
this.toggleLoader();
fetch(config.baseURL + 'mobileapi/get_token/?username=' + `${that.state.credentials.email}` + '&password=' + `${that.state.credentials.password}`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
credentials: credentials,
}),
})
.then((response) => response.json())
.then(responseJson => {
//stop loading after successful response
this.toggleLoader();
if (responseJson.confirmation === "success") {
AsyncStorage.setItem('USER_ID', responseJson.data.user_id);
AsyncStorage.setItem('USER_NAME', responseJson.data.user_name);
AsyncStorage.setItem('USER_TYPE', responseJson.data.user_email);
AsyncStorage.setItem('AUTHENTICATION_TOKEN', responseJson.data.token);
setTimeout(() => {
this.props.navigation.navigate("Home")
}, 500);
} else {
setTimeout(() => {
//code to handle an error
}, 500);
}
})
.catch((err) => {
//stop loading
this.toggleLoader();
setTimeout(() => {
if (JSON.stringify(err.message) === JSON.stringify('Network request failed')) {
alert('Please check your internet connection or try again later');
} else {
alert(JSON.stringify(err.message));
}
}, 500);
})
}
}
You have set email in TextInput like this.state.email. this should be this.state.credentials.email. same things sholud be follow for password. change onPress event of render() method like this:
render() {
const loginText = (this.state.loader) ? 'Loading' : 'Login';
return (
<View style={styles.container}>
<Image source={require('../../../../assets/images/icons/logo.png')}
style={{width: 99, height: 99, margin: 5,}}/>
<Text style={{fontSize: 20, margin: 20, color: "#0aa1e2"}}>Test App</Text>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/username.png')}/>
<TextInput style={styles.inputs}
placeholder="Username"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'email')
}}
value={this.state.credentials.email}
autoCorrect={false}
autoCapitalize={"none"}
/>
</View>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/password.png')}/>
<TextInput style={styles.inputs}
placeholder="Password"
secureTextEntry={true}
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'password')
}}
value={this.state.credentials.password}
autoCorrect={false}
secureTextEntry/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]}
onPress={this.login.bind(this)} >
<View style={{justifyContent: 'center', flex: 1, flexDirection: 'row'}}>
{this.state.loading === false ?
<Icon name='login' type='entypo' size={16} color='white'/> :
<ActivityIndicator size="small" color="#ffffff"/>}
<Text style={styles.loginText}> {loginText} </Text>
</View>
</TouchableHighlight>
</View>
);
}
TypeError: this.setState is not a function. This error is coming from updateText() method.you have added = during setState, which is throwing the error.
updateText(text, field) {
let newCredentials = Object.assign(this.state.credentials);
newCredentials[field] = text;
// setState should be done like this
this.setState({
credentials: newCredentials
})
}

React-Native how to not run function when starting the app?

I am currently learning how to create app using React Native and I am running into the issue of why is my app running the method when the app just started running?
I thought that I am only calling the function componentDidMount() in my button onPress ?
everything works fine as intended but I am just not sure why that's happening.
Thanks for your help!
import React from 'react';
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';
export default class App extends React.Component {
constructor(props){
super(props)
this.state = {
isLoading: true,
text: ''
}
}
componentDidMount(summonerIGN){
console.log("This is in summonerIGN", summonerIGN)
return fetch('https://na1.api.riotgames.com/lol/summoner/v3/summoners/by-name/' + summonerIGN +'?api_key=<APIKey>')
.then((response) => response.json())
.then((responseJson) => {
console.log("This is in responseJson", responseJson)
console.log("This is the summoner ID: ", responseJson.id)
this.setState({
isLoading: false,
dataSource: responseJson,
summonerID: responseJson.id,
summonerName: responseJson.name,
})
})
.catch((error) => {
console.error(error)
})
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Search For Summoner!"
onChangeText={(text) => this.setState({
text: text
})}
/>
<Button
onPress={() => {
console.log("This is in this.state.text", this.state.text)
this.componentDidMount(this.state.text)
}}
title="Search"
color="#841584"
/>
<Text style={{padding: 10, fontSize: 20}}>
Searching for summoner: {this.state.text}
</Text>
<Text>
The summpner ID: {this.state.summonerID}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
You can't just call componentDidMount().
It gets executed automatically once your component has been loaded.
Instead of writing logic in componentDidMount(), write a separate function and call that function.
componentDidMount() is a lifecycle method.
Lifecycle method gets called automatically based on components loads.
export default class App extends React.Component {
constructor(props){
super(props)
this.state = {
isLoading: true,
text: ''
}
}
callApi = (summonerIGN) => {
console.log("This is in summonerIGN", summonerIGN)
return fetch('https://na1.api.riotgames.com/lol/summoner/v3/summoners/by-name/' + summonerIGN +'?api_key=<APIKey>')
.then((response) => response.json())
.then((responseJson) => {
console.log("This is in responseJson", responseJson)
console.log("This is the summoner ID: ", responseJson.id)
this.setState({
isLoading: false,
dataSource: responseJson,
summonerID: responseJson.id,
summonerName: responseJson.name,
})
})
.catch((error) => {
console.error(error)
})
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Search For Summoner!"
onChangeText={(text) => this.setState({
text: text
})}
/>
<Button
onPress={() => {
console.log("This is in this.state.text", this.state.text)
this.callApi(this.state.text)
}}
title="Search"
color="#841584"
/>
<Text style={{padding: 10, fontSize: 20}}>
Searching for summoner: {this.state.text}
</Text>
<Text>
The summpner ID: {this.state.summonerID}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

App crashes in ios simulator when trying to use Phone auth in react-native firebase

I've followed the docs and did the necessary settings but the app crashes while launch. I'm not able to figure out the problem as to why this is occurring. any one who worked with rnfirebase? facing this issue?
import React, { Component } from 'react';
import { View, Button, Text, TextInput, Image } from 'react-native';
import firebase from 'react-native-firebase';
const successImageUri = 'https://cdn.pixabay.com/photo/2015/06/09/16/12/icon-803718_1280.png';
export default class App extends Component {
constructor(props) {
super(props);
this.unsubscribe = null;
this.state = {
user: null,
message: '',
codeInput: '',
phoneNumber: '+44',
confirmResult: null
};
firebase.initializeApp({
apiKey: 'AIzaSyAvKPtsqqqGjkGLkXD8BeqOR6GwJaI2AcE',
appId: '1:170852024080:ios:9bb19d2f74715186',
messagingSenderId: '170852024080',
projectId: 'chatapp-7c693',
authDomain: 'chatapp-7c693.firebaseapp.com',
databaseURL: 'https://chatapp-7c693.firebaseio.com',
storageBucket: 'chatapp-7c693.appspot.com'
});
}
componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({ user: user.toJSON() });
} else {
// User has been signed out, reset the state
this.setState({
user: null,
message: '',
codeInput: '',
phoneNumber: '+44',
confirmResult: null
});
}
});
}
//This is the example from the docs, so it must work
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();
}
signIn = () => {
const { phoneNumber } = this.state;
this.setState({ message: 'Sending code ...' });
firebase
.auth()
.signInWithPhoneNumber(phoneNumber)
.then(confirmResult => this.setState({ confirmResult, message: 'Code has been sent!' }))
.catch(error =>
this.setState({ message: `Sign In With Phone Number Error: ${error.message}` })
);
};
confirmCode = () => {
const { codeInput, confirmResult } = this.state;
if (confirmResult && codeInput.length) {
confirmResult
.confirm(codeInput)
.then(user => {
this.setState({ message: 'Code Confirmed!' });
})
.catch(error => this.setState({ message: `Code Confirm Error: ${error.message}` }));
}
};
signOut = () => {
firebase.auth().signOut();
};
renderPhoneNumberInput() {
const { phoneNumber } = this.state;
return (
<View style={{ padding: 25 }}>
<Text>Enter phone number:</Text>
<TextInput
autoFocus
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
onChangeText={value => this.setState({ phoneNumber: value })}
placeholder={'Phone number ... '}
value={phoneNumber}
/>
<Button title="Sign In" color="green" onPress={this.signIn} />
</View>
);
}
renderMessage() {
const { message } = this.state;
if (message.length) return null;
return <Text style={{ padding: 5, backgroundColor: '#000', color: '#fff' }}>{message}</Text>;
}
renderVerificationCodeInput() {
const { codeInput } = this.state;
return (
<View style={{ marginTop: 25, padding: 25 }}>
<Text>Enter verification code below:</Text>
<TextInput
autoFocus
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
onChangeText={value => this.setState({ codeInput: value })}
placeholder={'Code ... '}
value={codeInput}
/>
<Button title="Confirm Code" color="#841584" onPress={this.confirmCode} />
</View>
);
}
render() {
const { user, confirmResult } = this.state;
return (
<View style={{ flex: 1 }}>
{!user && !confirmResult && this.renderPhoneNumberInput()}
{this.renderMessage()}
{!user && confirmResult && this.renderVerificationCodeInput()}
{user && (
<View
style={{
padding: 15,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#77dd77',
flex: 1
}}
>
<Image
source={{ uri: successImageUri }}
style={{ width: 100, height: 100, marginBottom: 25 }}
/>
<Text style={{ fontSize: 25 }}>Signed In!</Text>
<Text>{JSON.stringify(user)}</Text>
<Button title="Sign Out" color="red" onPress={this.signOut} />
</View>
)}
</View>
);
}
}
can someone help? ive checked the docs again ..but no help ?idk
what more details I should add..this is my first question on stack
over flow..didnt know it was this annoying to ask a question...
I tried the web firebase sdk and can use the anonymous signin.. but I need phone auth which I'm not able to accomplish as it has different setups for ios and android ...rnfirebase is suppose to same as the web sdk
One of the few tricks will do
1. Add custom URL schemes to your Xcode project:
Open your project configuration: double-click the project name in
the left tree view. Select your app from the TARGETS section, then
select the Info tab, and expand the URL Types section.
Click the + button, and add a URL scheme for your reversed client ID.
To find this value, open the GoogleService-Info.plist configuration
file, and look for the REVERSED_CLIENT_ID key. Copy the value of that
key, and paste it into the URL Schemes box on the configuration page.
Leave the other fields blank.
more info here https://developers.google.com/identity/sign-in/ios/start-integrating
2. Run project from xcode then get back to terminal
Using Xcode, make sure you are opening the workspace file and not the project file. Run the it, once successfully built close Xcode get back to terminal react-native run-ios