React Native Keychain onPress function error - react-native

I've created an async const function for login purposes and after the credentials are set locally via the setGenericPassword method, the app navigates to the home screen. I want to execute this login function whenever the user presses on a specific button, marked as 'Log in'.
This is the error I'm getting when I try to execute the function with the button:
Promise-returning function provided to attribute where a void return was expected.
Async function code:
const login = async () => {
try {
await Keychain.setGenericPassword(firstName, lastName, options);
} catch (error) {
console.log(error);
}
navigation.navigate(SCREEN_NAMES.App.HomeStack.Home);
};
Button:
<Button
disabled={firstName === "" || lastName === "" || email === ""}
type="filled"
size="large"
text="Log in"
style={{ width: 160, height: 48, margin: 24 }}
onPress={() => login()}
/>
Unfortunately, I wasn't able to troubleshoot this issue myself, if anyone has any suggestions I would highly appreciate it.

Solved by using the useCallback Hook:
<Button
disabled={firstName === '' || lastName === '' || email === ''}
type='filled'
size='large'
text='Log in'
style={{ width: 160, height: 48, margin: 24 }}
onPress={useCallback(
() => {
login()
},
[firstName, lastName]
)}
/>

Related

How to prevent multiple clicks on a butoon in react native?

I'm working on a project that involves signing in users and it it is working fine (I'm using firebase for authentication). However for signing in to occur, it needs some time depending also on the internet connection so I need to disable the button once it is clicked and re-enable it again. Here is my code:
class Login extends Component {
handlelogin = () => {
this.setState.errorMessage = '';
const {email, password} = this.state;
auth
.signInWithEmailAndPassword(email, password)
.then(() => this.props.navigation.navigate('Home'))
.catch((error) => this.setState({errorMessage: error.message}));
};
render() {
return (
// Some code to handle input
<TouchableOpacity
style={
!this.state.email || !this.state.password
? styles.disabled
: styles.button
}
disabled={!this.state.password || !this.state.email}
onPress={this.handlelogin}>
<Text style={{color: '#fff', fontWeight: '500'}}>Sign in</Text>
</TouchableOpacity>
)}
I have tried this answer for my code to go like this but this didn't seem to work:
class Login extends Component {
loginProcess = false;
handlelogin = () => {
this.setState.errorMessage = '';
const {email, password} = this.state;
auth
.signInWithEmailAndPassword(email, password)
.then(() => this.props.navigation.navigate('Home'))
.catch((error) => {
this.setState({errorMessage: error.message})
this.loginProcess = false;
});
};
render() {
return (
// Some code to handle input
<TouchableOpacity
style={
!this.state.email || !this.state.password
? styles.disabled
: styles.button
}
disabled={!this.state.password || !this.state.email}
onPress={()=> {
if (!loginProcess) {
this.handleLogin;
this.loginProcess = true;
}
}>
<Text style={{color: '#fff', fontWeight: '500'}}>Sign in</Text>
</TouchableOpacity>
)}
P.S This is my first question on stackoverflow, any hint for writing better questions is appreciated
You could implement a Spinner that shows instead of the button when it is first clicked and shows the button after the call finishes.
I had the same problem not long ago - here a small example:
const MyComponent = ({makePutCall}) => {
const [showSpinner,setShowSpinner] = useState(false);
const handlePress = async () => {
setShowSpinner(true);
await makePutCall();
setShowSpinner(false);
}
return showSpinner ? <Spinner/> : <Button onPress={handlePress}/>
}
as a "Spinner" just use ActivityIndicator from react-native.

updating state using name attribute on TextInput react-native

i'm attempting to update a state onChange within a form. When I type in the form my app crashes with this error
TypeError undefined is not an object react-native (evaluating e.target)
I'm trying to use [e.target.name] to select the appropriate state to update using my elements.
maybe i'm missing something small but I have pretty much the exact same code running in a react web project and it works fine?
here's my current form
export default class CreateNote extends Component {
state = {
modalVisible: false,
title: "",
who: "",
time: ""
};
setModalVisible(visible) {
this.setState({ modalVisible: visible });
}
onTextChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
createNoteView=()=>{
if(this.state.modalVisible === true){
return (
<View style={{ marginTop: 10 }}>
<Button title="cancel" onPress={()=>this.setState({modalVisible:false})}></Button>
<TextInput
placeholder="title"
name = "title"
type="text"
onChange={()=>{this.onTextChange()}}
/>
<TextInput
placeholder="who"
name = "who"
type="text"
onChange={()=>{this.onTextChange()}}
/>
<TextInput
placeholder="when"
name = "time"
type="text"
onChange={()=>{this.onTextChange()}}
/>
</View>
)
}
return (
<View style={{ marginTop: 22, width: 150 }}>
<Button onPress={()=>{this.setModalVisible(!this.state.modalVisible)}} title="create"></Button>
</View>
)
}
render() {
return(
<View>
{this.createNoteView()}
</View>
)
}
}
You should use onChangeText method like below.
onTextChange = (name) => (value) => {
this.setState({ [name]: value });
};
...other code...
<TextInput
placeholder="title"
onChangeText={this.onTextChange("title")}
/>
You can refer onChangeText here
If you want to use onChange instead of onChangeText then you should use somthing like event.nativeEvent.text
onTextChange = (name) => (event) => {
this.setState({ [name]: event.nativeEvent.text });
};
...other code...
<TextInput
placeholder="title"
onChange={this.onTextChange("title")}
/>

React Navigation passing data with function call on navigate

I'm trying to pass a variable (i can do this) and run a function with that variable as soon as navigation happened.
Function takes value of a input field. But because i assigned input field to my variable i'm having some trouble on render method because it overwrites the data after navigation or not even write it. It works when manually input but i need to pass this variable from camera also(this also works fine).
Main Page
onChange(obj) {
const value = obj;
if (value) {
this.setState({
buttonDisabled: false,
text: value,
});
} else {
this.setState({
buttonDisabled: true,
text: ''
});
}
};
render() {
const { navigation } = this.props;
const scanCode = navigation.getParam('text', '');
return (
<View style={{padding: 30, paddingTop: 40}}>
<TextInput autoFocus
ref='queryInput'
style={{height: 40}}
placeholder="placeholder.."
value={scanCode === '' ? this.state.text : scanCode}
onChangeText={this.onChange.bind(this)}
onSubmitEditing={this.runQuery}
/>
<Button
onPress={this.runQuery}
title="run"
color="#841584"
accessibilityLabel="query"
disabled={this.state.buttonDisabled}
/>
<Button title='Camera' style={{position: 'absolute', bottom: 0, left: 0}} onPress={() => this.gotoCamera()}></Button>
</View>
);
}
};
Camera Page
gotoMainPage = () => {
this.props.navigation.navigate('Home', {
text: this.state.qrcode
})
}
onBarCodeRead = (e) => this.setState({qrcode: e.data}, () => this.gotoMainPage());
is it possible to setState of a value in Main page from Camera Page or what should i do here?
Thanks

react native modal does not open

I am creating signup form and trying to sign in with phone number which returns verification code which i wanted to type in modal windrow. I wanted to open modal window after signup button has been click.I have sent visible property of modal to true but it is not being displayed on the screen. i have check the console value for the visibility property which is showing me "true" , which i could understand my modal will opn successfully but it is not doing anything. There is no errors also.
My code:
signIn = () => {
const { name, password, confirmPassword, mobile } = this.props;
const object = { confirmPassword, password };
const error = Validator('name', name)
|| Validator('password', password)
|| PasswordValidator(object)
|| Validator('mobile', mobile);
const mobileNo = '+91'+mobile;
if (error != null) {
Alert.alert('Error', error);
} else {
console.log('else');
const mobile = this.props.mobile;
const userRef = firebase.database().ref(`/users/`);
userRef.once('value', function(snapshot) {
//If user is existed redirect to login page
if(snapshot.val().mobile == mobile){
Alert.alert('Error', 'Phone number is already registered! Please login with your credentials');
NavigationService.navigate('Login');
}
});
}
// If user is not exist signup
firebase.auth().signInWithPhoneNumber(mobileNo)
.then(confirmResult => this.setState({ confirmResult, message: 'Code has been sent!' },
this.renderVerificationCodeInput()
))
.catch(error => this.setState({ message: `Sign In With Phone Number Error: ${error.message}` }));
};
renderVerificationCodeInput() {
console.log('code');
const { codeInput } = this.state;
this.setModalVisible(!this.state.modalVisible);
console.log(this.state.modalVisible);
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
console.log('Modal has been closed');
}}
>
{console.log(this.state.modalVisible)}
<View >
<Text>Enter verification code below:</Text>
<Input
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>
</Modal>
</View>
}
I don't know if its all the code,
if not you need to add state
state = {modalVisible: false}
and replace this.setModalVisible(!this.state.modalVisible);
to this.setState({modalVisible:!this.state.modalVisible)

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