Email address is badly formatted error without even typing anything - react-native

I am trying to do firebase authentication using email and password for my expo app. On the login screen, if i press on the login button, it gives me the above message, " email address is badly formatted'.
The signup button should navigate to sign up page, but clicking on the button also gives me the same error.
export default class App extends React.Component{
constructor(props)
{ super(props);
this.state = { isLoadingComplete: false,
};
if (!firebase.apps.length){firebase.initializeApp(ApiKeys.FirebaseConfig );}
}
render()
{
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
{Platform.OS === 'android' && <View style={styles.statusBarUnderlay} />}
{ <AppNavigator/> }
</View>
);
}
}
_loadResourcesAsync = async () => {
return Promise.all([
Asset.loadAsync([
require('./assets/images/robot-dev.png'),
require('./assets/images/robot-prod.png'),
]),
Font.loadAsync({
...Ionicons.font,
'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
}),
]);
};
_handleLoadingError = error => {
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
statusBarUnderlay: {
height: 24,
backgroundColor: 'rgba(0,0,0,0.2)',
},
});
## login page
export default class LoginScreen extends React.Component {
constructor(props)
{
super(props);
this.state = {
email:' ' ,password:' ',
}
}
LoginButtonPress= (email, password) =>
{
try{
firebase.auth().signInWithEmailAndPassword(this.state.email.trim(), this.state.password)
.then(function(user){console.log(user)
})
}
catch(error){
Alert.alert(error.message);
}
}
render()
{
return (
<ScrollView style= {styles.container}>
<Container style ={styles.container}>
<Content>
<Form>
<Item floatingLabel>
<Label> Email Address</Label>
<Input autoCorrect = {false} autoCapitalize ="none"
onChangeText= {(email) => this.setState({email})}/>
</Item>
<Item floatingLabel>
<Label> Password</Label>
<Input secureTextEntry ={true}
autoCorrect = {false}
autoCapitalize = "none"
onChangetext = { (password)=> this.setState({password})}/>
</Item>
<Button success info onPress ={()=>this.LoginButtonPress(this.state.email, this.state.password)}>
<Text> LogIn </Text>
</Button>
<Button primary onPress = {()=> this.props.navigation.navigate('SignupScreen')}>
<Text> First Time User? SignUpNow </Text>
</Button>
<Button onPress ={()=> this.props.navigation.navigate('ResetPassScreen')}>
<Text> Forgot Password? Reset Now </Text>
</Button>
</Form>
</Content>
</Container>
</ScrollView>
);
}}
##signup page
export default class SignupScreen extends React.Component{
constructor(props)
{
super(props);
this.state = { email: '',
password:''
}
}
SignUpButtonPress= (email, password)=>
{
try {
firebase.auth().createUserWithEmailAndPassword(this.state.email.trim(), this.state.password)
}
catch(error){
Alert.alert(error.message);
}
}
render ()
{
return (
<ScrollView>
<Container style = {styles.container}>
<Content>
<Form>
<Item floatingLabel>
<Label> Email Address</Label>
<Input autoCapitalize = "none" autoCorrect ={false} emailonChangeText ={(email)=>this.setState({email})} />
</Item>
<Item floatingLabel>
<Label> Password</Label>
<Input secureTextEntry = {true} onChangeText ={(password)=>this.setState({password})} />
</Item>
<Button success info onPress = {this.SignUpButtonPress(this.state.email, this.state.password)}>
<Text> SignUp </Text>
</Button>
</Form>
</Content>
</Container>
</ScrollView>
);
}

Your onPress for the signup button is immediately calling the SignupButtonPress callback on every render. Change
// notice that `onPress` is directly calling `this.SignUpButtonPress`
<Button success info onPress = {this.SignUpButtonPress(this.state.email, this.state.password)}>
To
<Button success info onPress = {() => {this.SignUpButtonPress(this.state.email, this.state.password);}}>

Related

Warning: Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Context.consumer`)

here my context file
import React from 'react';
import storage from '#helper/storage/user-storage';
export const AuthContext = React.createContext();
class AuthContextProvider extends React.Component{
state = {
user: null,
nigth_mode: false,
token: null
}
login = async ({user, token}) => {
await storage.storeUser(user)
await storage.storeToken(token)
this.setState({
user: user,
token: token
})
}
logout = async () => {
storage.removeAll().then(() => {
this.setState({
user: null,
token: null
})
});
}
setUser = async (data) => {
this.setState({
user: data
})
}
nigth_mode = async () => {
this.setState({
nigth_mode: !nigth_mode
})
}
render(){
return(
<AuthContext.Provider
value={{
...this.state,
login: this.login,
logout: this.logout,
setUser: this.setUser,
nigth_mode: this.nigth_mode,
token: this.state.token
}}
>
{ this.props.children }
</AuthContext.Provider>
);
}
}
export default AuthContextProvider
in my login file i have this render
render(){
return(
<AuthContext.Consumer>
{context => {
console.log('token', context)
if(context.token){
// this.props.navigation.reset({
// index: 0,
// routes: [{ name: 'Home' }],
// });
this.props.navigation.navigate('View')
}else{
return(
<LinearGradient
colors={['#232526', '#182848']}
style={styles.mainContainerLogin}>
<KeyboardAvoidingView
style={styles.mainContainerLogin}
behavior={'height'}
>
{/* <View style={styles.loginLogo}>
<Image
source={require('../Images/ic-logo.jpg')}
style={styles.logo}
/>
</View> */}
<View style={styles.inputContainer}>
<Ionicon
name="md-person"
size={20}
color="rgb(110,182,245)"
style={styles.inputIcon}
/>
<TextInput
placeholder={'Email'}
placeholderTextColor={'rgba(255,255,255,0.5)'}
underlineColorAndroid="transparent"
style={styles.loginInput}
onChangeText={value => (this.userref = value)}
/>
</View>
<View style={styles.inputContainer}>
<Ionicon
name="md-lock-closed"
size={20}
color="rgb(110,182,245)"
style={styles.inputIcon}
/>
<TextInput
placeholder="Password"
placeholderTextColor={'rgba(255,255,255,0.5)'}
underlineColorAndroid="transparent"
secureTextEntry={this.state.keyHide}
style={styles.loginInput}
onChangeText={value => (this.password = value)}
/>
<TouchableOpacity
style={styles.btnEye}
onPress={this._showPassword.bind(this)}>
<Ionicon
name={
this.state.press == false ? 'md-eye' : 'md-eye-off'
}
size={20}
color="rgb(110,182,245)"
/>
</TouchableOpacity>
</View>
{this._displayLoading()}
{_errorTextLogin(this.state.error)}
</KeyboardAvoidingView>
</LinearGradient>
);
}
}}
</AuthContext.Consumer>
);
so on clicking login button, the context.login is called, so it's set the state of token, so in my condition if my context.token exist i navigate to another page; if i console log on context.token, i got eh token when login is success,then the navigation is processed successfuly but i got a error popup on the new page
Warning: Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Context.consumer`)

React Native reusable edit component

I'm trying to create a reusable component in react native. The idea is to have only one component responsible to edit all the fields that I have.
Main Component
...
constructor(props) {
super(props);
this.state.FirstName = 'Joe'
}
...
const { FirstName } = this.state.FirstName;
<TouchableOpacity
onPress={() =>
NavigationService.navigate('EditData', {
label: 'First Name',
initialValue: FirstName,
onSubmit: (FirstName) => this.setState({ FirstName })
})
}
>
<CardItem>
<Left>
<FontAwesome5 name="user-edit" />
<Text>First Name</Text>
</Left>
<Right>
<Row>
<Text style={styles.valueText}>{FirstName} </Text>
<Icon name="arrow-forward" />
</Row>
</Right>
</CardItem>
</TouchableOpacity>
// Keep doing the same for other fields
Then, the edit component should be reusable.
constructor(props) {
super(props);
// callback function
this.onSubmit = props.navigation.getParam('onSubmit');
// label/value
this.state = {
label: props.navigation.getParam('label'),
value: props.navigation.getParam('initialValue')
};
}
render() {
const { onSubmit } = this;
const { label, value } = this.state;
return (
<Container>
<Header />
<Content>
<Item floatingLabel style={{ marginTop: 10 }}>
<Label>{label}</Label>
<Input
value={value}
onChangeText={val => this.setState({ value: val })}
/>
</Item>
<Button
onPress={() => {
onSubmit(value);
NavigationService.navigate('TenantDetails');
}
}
>
<Text>OK</Text>
</Button>
</Content>
</Container>
);
}
When back to the main component, the first name value was not changed.
My NavigationService in case it might be the problem:
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
Thanks
You could pass a callback to your new component which handles this. The new component would start with a state with the initialValue set. It looks like you might be using react-navigation so I would recommend that if you want this component on its own screen you could do
this.navigation.navigate('SetValueScreen', {
initialValue: this.state.email,
onSubmit: (email) => this.setState({ email })
})
and on the SetValueScreen get the initialValue in the constructor and in the render use the callback
class SetValueScreen extends React.PureComponent{
constructor(props){
super(props)
this.onSubmit = props.navigation.getParam('onSubmit');
this.state = {
value: props.navigation.getParam('initialValue')
}
}
render(){
const { onSubmit } = this
const { value } = this.state
return (
...
<Right>
<TextInput value={value} onChangeText={(value) => setState({ value })} />
</Right>
<Button onPress={() => {
onSubmit(value)
navigation.goBack()
}} >
OK
</Button>
...
)
}
}
I hope this helps.

When text input is filled, button doesn't submit

The button's onPress function is called when neither of text fields above are filled. Otherwise, I press the button and nothing happens. I've tried change the onPress to onPress={this.handleSubmit()} but then the function is called before any data is in the TextInput's and an error is thrown. I've also tried using the tcomb-form-native package, but the problem persists. What do I need to change to get the handleSubmit function to be called when the text inputs are filled?
handleSubmit = () => {
console.log('handle submit')
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40}}
placeholder="Your name"
onChangeText={userName => this.setState({userName})}
/>
<TextInput
style={{height: 40}}
placeholder="other name"
onChangeText={otherName => this.setState({otherName})}
/>
<Button
title="Name"
onPress={this.handleSubmit}
/>
</View>
);
}
Have you tried using
e.preventDefault()
?
handleSubmit = (e) => {
e.preventDefault()
console.log('handle submit')
}
constructor(props){
super(props);
this.state = {
userName: '',
otherName: ''
};
}
handleSubmit = () => {
// Check if any of them is empty then do nothing
if(!this.state.otherName || !this.state.userName){return;}
console.log('handle submit');
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40}}
placeholder="Your name"
onChangeText={userName => this.setState({userName})}
/>
<TextInput
style={{height: 40}}
placeholder="other name"
onChangeText={otherName => this.setState({otherName})}
/>
<Button
title="Name"
onPress={this.handleSubmit}
/>
</View>
);
}

Render handler to be called when the user hits return key

I am creating a todo list. For the TextInput I do not want to use a button and the "onPress: () =>" handler to call my function with the users given text. Instead, I would like the user to just be able to hit the return key to call my function. It doesn't seem that react-native has an "onReturnKey" handler. Any suggestions for how I should go about this?
...
class App extends Component {
constructor(props) {
super(props);
this.state = { newTodo: '' };
}
AddNewTodo(text) {
return console.log(text);
}
render() {
return (
<View>
<Header headerText="VANO" />
<Card>
<CardSection style={{ backgroundColor: '#f7f7f7' }}>
<Text style={styles.titleStyle}>
Reminders
</Text>
</CardSection>
<CardSection>
<Input
placeholder="Create Reminder"
returnKeyType='done'
onChangeText={(text) => this.setState(this.newTodo: text)}
onSubmitEditing={() => this.AddNewTodo(this.state.newTodo)}
value={this.state.newTodo}
/>
</CardSection>
...
The TextInput component has a prop for returnKeyType. You can use that in conjunction with onSubmitEditing to run a function when the return key is pressed.
Example:
constructor() {
this.state = { new_todo: '' }
}
render() {
return (
....
<TextInput
returnKeyType={"done"}
onChangeText={(text) => { this.setState(new_todo: text) }}
onSubmitEditing={() => { myFunctionToAddNewTodo(this.state.new_todo) }}
value={this.state.new_todo}/>
...
)
}

react native get TextInput value

I am stuck with a very simple problem. I have login form with username, password and button. In my button handler, I try to get the textinput value. But always get undefined value. Am I missing something?
render() {
<ExScreen
headerColor={this.state.headerColor}
scrollEnabled={this.state.enableScroll}
style={styles.container} >
<View >
<View >
<View style={[styles.inputContainer]} >
<TextInput
ref= "username"
onChangeText={(text) => this.setState({text})}
value={this.state.username}
/>
</View>
<Button style={{color: 'white', marginTop: 30, borderWidth: 1, borderColor: 'white', marginLeft: 20*vw, marginRight: 20*vw, height: 40, padding: 10}}
onPress={this._handlePress.bind(this)}>
Sign In
</Button>
...
_handlePress(event) {
var username=this.refs.username.value;
The quick and less optimized way to do this is by using arrow function inside your onChangeText callback, by passing username as your argument in your onChangeText callback.
<TextInput
ref= {(el) => { this.username = el; }}
onChangeText={(username) => this.setState({username})}
value={this.state.username}
/>
then in your _handlePress method
_handlePress(event) {
let username=this.state.username;
}
But this has several drawbacks!!!
On every render of this component a new arrow function is created.
If the child component is a PureComponent it will force re-renders unnecessarily, this causes huge performance issue especially when dealing with large lists, table, or component iterated over large numbers. More on this in React Docs
Best practice is to use a handler like handleInputChange and bind ```this`` in the constructor.
...
constructor(props) {
super(props);
this.handleChange= this.handleChange.bind(this);
}
...
handleChange(event = {}) {
const name = event.target && event.target.name;
const value = event.target && event.target.value;
this.setState([name]: value);
}
...
render() {
...
<TextInput
name="username"
onChangeText={this.handleChange}
value={this.state.username}
/>
...
}
...
Or if you are using es6 class property shorthand which autobinds this. But this has drawbacks, when it comes to testing and performance. Read More Here
...
handleChange= (event = {}) => {
const name = event.target && event.target.name;
const value = event.target && event.target.value;
this.setState([name]: value);
}
...
render() {
...
<TextInput
name="username"
onChangeText={this.handleChange}
value={this.state.username}
/>
...
}
...
You should use States to store the value of input fields.
https://facebook.github.io/react-native/docs/state.html
To update state values use setState
onChangeText={(value) => this.setState({username: value})}
and get input value like this
this.state.username
Sample code
export default class Login extends Component {
state = {
username: 'demo',
password: 'demo'
};
<Text style={Style.label}>User Name</Text>
<TextInput
style={Style.input}
placeholder="UserName"
onChangeText={(value) => this.setState({username: value})}
value={this.state.username}
/>
<Text style={Style.label}>Password</Text>
<TextInput
style={Style.input}
placeholder="Password"
onChangeText={(value) => this.setState({password: value})}
value={this.state.password}
/>
<Button
title="LOGIN"
onPress={() =>
{
if(this.state.username.localeCompare('demo')!=0){
ToastAndroid.show('Invalid UserName',ToastAndroid.SHORT);
return;
}
if(this.state.password.localeCompare('demo')!=0){
ToastAndroid.show('Invalid Password',ToastAndroid.SHORT);
return;
}
//Handle LOGIN
}
}
/>
In React Native 0.43: (Maybe later than 0.43 is OK.)
_handlePress(event) {
var username= this.refs.username._lastNativeText;
If you are like me and doesn't want to use or pollute state for one-off components here's what I did:
import React from "react";
import { Text, TextInput } from "react-native";
export default class Registration extends Component {
_register = () => {
const payload = {
firstName: this.firstName,
/* other values */
}
console.log(payload)
}
render() {
return (
<RegisterLayout>
<Text style={styles.welcome}>
Register
</Text>
<TextInput
placeholder="First Name"
onChangeText={(text) => this.firstName = text} />
{/*More components...*/}
<CustomButton
backgroundColor="steelblue"
handlePress={this._register}>
Submit
</CustomButton>
</RegisterLayout>
)
}
}
export default class App extends Component {
state = { username: '', password: '' }
onChangeText = (key, val) => {
this.setState({ [key]: val})
}
render() {
return (
<View style={styles.container}>
<Text>Login Form</Text>
<TextInput
placeholder='Username'
onChangeText={val => this.onChangeText('username', val)}
style={styles.input}
/>
<TextInput
placeholder='Password'
onChangeText={val => this.onChangeText('password', val)}
style={styles.input}
secureTextEntry={true}
/>
</View>
);
}
}
Hope this will solve your problem
This work for me
<Form>
<TextInput
style={{height: 40}}
placeholder="userName"
onChangeText={(text) => this.userName = text}
/>
<TextInput
style={{height: 40}}
placeholder="Password"
onChangeText={(text) => this.Password = text}
/>
<Button
title="Sign in!"
onPress={this._signInAsync}
/>
</Form>
and
_signInAsync = async () => {
console.log(this.userName)
console.log(this.Password)
};
Please take care on how to use setState(). The correct form is
this.setState({
Key: Value,
});
And so I would do it as follows:
onChangeText={(event) => this.setState({username:event.nativeEvent.text})}
...
var username=this.state.username;
Try Console log the object and you will find your entered text inside nativeEvent.text
example:
handelOnChange = (enteredText) => {
console.log(enteredText.nativeEvent.text)
}
render()
return (
<SafeAreaView>
<TextInput
onChange={this.handelOnChange}
>
</SafeAreaView>
)
constructor(props) {
super(props);
this.state ={
commentMsg: ''
}
}
onPress = () => {
alert("Hi " +this.state.commentMsg)
}
<View style={styles.sendCommentContainer}>
<TextInput
style={styles.textInput}
multiline={true}
onChangeText={(text) => this.setState({commentMsg: text})}
placeholder ='Comment'/>
<Button onPress={this.onPress}
title="OK!"
color="#841584"
/>
</TouchableOpacity>
</View>
Simply do it.
this.state={f_name:""};
textChangeHandler = async (key, val) => {
await this.setState({ [key]: val });
}
<Textfield onChangeText={val => this.textChangeHandler('f_name', val)}>
Every thing is OK for me by this procedure:
<Input onChangeText={this.inputOnChangeText} />
and also:
inputOnChangeText = (e) => {
this.setState({
username: e
})
}
React Native Latest -> Simple and easy solution using state based approach.
const [userEmail, setUserEmail] = useState("");
<TextInput
value={userEmail}
style={styles.textInputStyle}
placeholder="Email"
placeholderTextColor="steelblue"
onChangeText={(userEmail) => setUserEmail(userEmail)}
/>
If you set the text state, why not use that directly?
_handlePress(event) {
var username=this.state.text;
Of course the variable naming could be more descriptive than 'text' but your call.
There is huge difference between onChange and onTextChange prop of <TextInput />. Don't be like me and use onTextChange which returns string and don't use onChange which returns full objects.
I feel dumb for spending like 1 hour figuring out where is my value.
You dont need to make a new function for taht.
just make a new useState and use it in onchange.
const UselessTextInput = () => {
const [text, onChangeText] = React.useState("Useless Text");
const [number, onChangeNumber] = React.useState(null);
return (
<SafeAreaView>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
/>
<TextInput
style={styles.input}
onChangeText={onChangeNumber}
value={number}
placeholder="useless placeholder"
keyboardType="numeric"
/>
</SafeAreaView>
);
};
This piece of code worked for me. What I was missing was I was not passing 'this' in button action:
onPress={this._handlePress.bind(this)}>
--------------
_handlePress(event) {
console.log('Pressed!');
var username = this.state.username;
var password = this.state.password;
console.log(username);
console.log(password);
}
render() {
return (
<View style={styles.container}>
<TextInput
ref="usr"
style={{height: 40, borderColor: 'gray', borderWidth: 1 , marginTop: 10 , padding : 10 , marginLeft : 5 , marginRight : 5 }}
placeHolder= "Enter username "
placeholderTextColor = '#a52a2a'
returnKeyType = {"next"}
autoFocus = {true}
autoCapitalize = "none"
autoCorrect = {false}
clearButtonMode = 'while-editing'
onChangeText={(text) => {
this.setState({username:text});
}}
onSubmitEditing={(event) => {
this.refs.psw.focus();
}}
/>
<TextInput
ref="psw"
style={{height: 40, borderColor: 'gray', borderWidth: 1 , marginTop: 10,marginLeft : 5 , marginRight : 5}}
placeholder= "Enter password"
placeholderTextColor = '#a52a2a'
autoCapitalize = "none"
autoCorrect = {false}
returnKeyType = {'done'}
secureTextEntry = {true}
clearButtonMode = 'while-editing'
onChangeText={(text) => {
this.setState({password:text});
}}
/>
<Button
style={{borderWidth: 1, borderColor: 'blue'}}
onPress={this._handlePress.bind(this)}>
Login
</Button>
</View>
);``
}
}
User in the init of class:
constructor() {
super()
this.state = {
email: ''
}
}
Then in some function:
handleSome = () => {
console.log(this.state.email)
};
And in the input:
<TextInput onChangeText={(email) => this.setState({email})}/>
Did you try
var username=this.state.username;