React-Native Big Problems with Confirming Password - reactjs

i got a Questions because I am new in React native! I was trying to find an Answer that fits with my Code. But nothing is working well! Im overloaded. Maybe some of u guys can help me with my problem!
So i need a "simple" confirming password message if someone is writing the two fields wrong because there is no match!
import React, { Component } from 'react';
import {View, Image, TextInput} from 'react-native';
import { Container, Header, Content, Button, Icon, Body, Left, Right,
Text, Title, Card, CardItem } from 'native-base';
import styles from '../Style/Style.js'
import Foect from 'foect';
import IconNew from 'react-native-vector-icons/MaterialIcons';
export default class AnmeldeScreen extends Component {
constructor(props) {
super(props);
this.state = {
icEye: 'visibility-off',
password: true,
}
}
static navigationOptions = {
header: null
}
changePwdType = () => {
let newState;
if (this.state.password) {
newState = {
icEye: 'visibility',
password: false
}
} else {
newState = {
icEye: 'visibility-off',
password: true
}
}
// set new state value
this.setState(newState)
};
render () {
var {navigate} = this.props.navigation;
return (
<Container>
{/*---------------------------------------------------- H E A D E R ------------------------------------------------------------*/}
<Header>
<Left>
<Button transparent onPress={() => navigate("Start", {})}>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title style={styles.titelintervall}>Registrieren</Title>
</Body>
<Right>
</Right>
</Header>
{/*---------------------------------------------------- C O N T E N T ------------------------------------------------------------*/}
<Content padder>
<Image source={require('../images/low-carb-camp-logo-breit.png')} style={styles.secondimagelogo} />
<Foect.Form
defaultValue={{
email: ''
}}
onValidSubmit={model => {
console.log(model);
}}
>
{ /* you can use form for triggering submit or checking form state(form.isSubmitted, form.isValid, ...) */ }
{ form => (
<View>
{ /* every Foect.Control must have a name and optionally validation rules */ }
<Foect.Control name="fullName" required minLength={2} maxLength={32}>
{ /* you can use control for getting/setting it's value, checking/updating(control.isValid, control.markAsTouched(), ...) it's state, checking it's errors(control.errors.required) */ }
{ control => (
<View>
<Text style={{ marginTop: 10, color: '#8BC051' }}>Dein Name</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderBottomWidth: 1}}
/* mark control as touched on blur */
onBlur={control.markAsTouched}
/* update control's value */
onChangeText={(text) => control.onChange(text)}
/* get control's value */
value={control.value}
placeholder="Hier vollständigen Namen eingeben"
/>
{ /* check control state and show error if necessary */ }
{ control.isTouched &&
control.isInvalid &&
<Text style={{ color: 'red' }}>Bitte trage deinen Namen ein.</Text> }
</View>
) }
</Foect.Control>
<Foect.Control name="email" required email>
{ control => (
<View>
<Text style={{ marginTop: 10, color: '#8BC051' }}>Email</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderBottomWidth: 1}}
keyboardType="email-address"
onBlur={control.markAsTouched}
onChangeText={(text) => control.onChange(text)}
value={control.value}
placeholder="Hier E-Mail eingeben"
/>
{ control.isTouched &&
control.isInvalid &&
<View>
<Text style={{ color: 'red'}}>{control.value} ist keine gültige E-Mail</Text>
</View> }
</View>
) }
</Foect.Control>
<Foect.Control name="password" required pattern={/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/}>
{ control => (
<View>
<Text style={{ marginTop: 10, color: '#8BC051' }}>Passwort
</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderBottomWidth: 1}}
secureTextEntry={true}
onBlur={control.markAsTouched}
onChangeText={(text) => control.onChange(text)}
value={control.value}
secureTextEntry={this.state.password}
placeholder="Passwort erstellen"
/>
<IconNew style={styles.icon}
name={this.state.icEye}
size={25}
color={this.props.iconColor}
onPress={this.changePwdType}
/>
{ control.isTouched &&
control.isInvalid &&
<View>
{ control.errors.pattern ?
<Text style={{ color: 'red' }}>Dein Passwort muss mindestens 8 Zeichen lang sein und mindestens ein Sonderzeichen oder eine Zahl enthalten.</Text> :
<Text style={{ color: 'red' }}>Bitte trage dein Passwort ein.</Text> }
</View> }
</View>
) }
</Foect.Control>
<Foect.Control name="confirmpassword">
{ control => (
<View>
<Text style={{ marginTop: 10, color: '#8BC051' }}>Passwort wiederholen
</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderBottomWidth: 1}}
secureTextEntry={true}
onBlur={control.markAsTouched}
onChangeText={(text) => control.onChange(text)}
value={control.value}
placeholder="Passwort bitte wiederholen"
/>
</View>
) }
</Foect.Control>
</View>
) }
</Foect.Form>
<View style={{marginTop: 10}}>
<Button full warning style={styles.buttonintervall} onPress={
() => navigate("Ziel", {})}>>>
<Text>Registrieren</Text>
</Button>
</View>
<Text style={styles.secondtextfb}> oder </Text>
<Card>
<CardItem>
<Icon name="logo-facebook" style={{color: '#234c6e'}} />
<Text>Über Facebook registrieren</Text>
<Right>
<Icon name="arrow-forward" />
</Right>
</CardItem>
</Card>
</Content>
</Container>
);
}
}

Related

React Native Update Parent Array from Child Component

I am having trouble updating an array that is passed as a prop into my child component. I have searched around but haven't found an answer that can directly solve my problem. My code is as follows:
App.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, SafeAreaView } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import AddMedication from "./src/AddMedication";
import MedicationList from './src/MedicationList';
const Stack = createNativeStackNavigator();
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
medications: [],
}
this.addMedication = this.addMedication.bind(this);
}
addMedication = (name, dosage, measurement, timesDaily) => {
console.log("Medication added.")
var newItem = {name: name, dosage: dosage, measurement: measurement, timesDaily: timesDaily}
this.setState({
medications: [...this.state.medications, newItem]
})
}
render() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Medication List">
{(props) => <MedicationList {...props} medications={this.state.medications} />}
</Stack.Screen>
<Stack.Screen name="Add New Medication">
{(props) => <AddMedication {...props} addMedication={this.addMedication} />}
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
}
}
This is the home screen where I am trying to display the array but nothing shows up
MedicationList.js
class MedicationList extends Component {
constructor(props) {
super(props);
this.state = {
tableHead: ['Name', 'Dosage', 'Times Daily', 'Prescriber', 'For Diagnosis'],
}
}
medication = ({ item }) => {
<View style={{ flexDirection: 'row' }}>
<View style={{ width: 50, backgroundColor: 'lightyellow'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold', textAlign: 'center'}}>{item.name}</Text>
</View>
<View style={{ width: 400, backgroundColor: 'lightpink'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold' , textAlign: 'center'}}>{item.dosage}{item.selectedMeasurement}</Text>
</View>
<View style={{ width: 400, backgroundColor: 'lavender'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold' , textAlign: 'center'}}>{item.timesDaiy}</Text>
</View>
</View>
}
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', marginTop: '10%'}}>
<Button
title="+ Add New Medication"
onPress={() => {
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate('Add New Medication', {
medications: this.props.medications,
});
}}
/>
<FlatList
data={this.props.medications}
renderItem={this.medication}
/>
</View>
);
}
}
This is where I click the add button to update the medications array
AddMedication.js
class AddMedication extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
dosage: 0,
selectedMeasurement: "mg",
timesDaily: '',
prescriber: '',
forDiagnoses: '',
instructions: '',
validity: false,
};
}
setName = (name) => {
let isValid = this.isFormValid();
this.setState({ name: name, validity: isValid });
}
setDosage = (dosage) => {
let isValid = this.isFormValid();
this.setState({ dosage: dosage, validity: isValid });
}
setMeasurement = (measurement) => {
this.setState({ selectedMeasurement: measurement });
}
setTimesDaily = (timesDaily) => {
let isValid = this.isFormValid();
this.setState({ timesDaily: timesDaily, validity: isValid });
}
setPrescriber = (prescriber) => {
this.setState({ prescriber: prescriber });
}
setDiagnoses = (diagnoses) => {
this.setState({ forDiagnoses: diagnoses });
}
setInstructions = (instructions) => {
this.setState({ instructions: instructions });
}
isFormValid = () => {
return (this.state.name !== '' && (this.state.dosage !== '' && this.state.dosage > 0)
&& (this.state.timesDaily !== '' && this.state.timesDaily > 0));
}
render() {
return (
<View style={styles.container}>
<Text style={{color: 'red', marginBottom: 5, marginLeft: -125}}>* denotes required field</Text>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(name) => this.setName(name)}
placeholder="Medication Name"
value={this.state.name}
/>
</View>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(dosage) => this.setDosage(dosage)}
placeholder="Dosage"
value={this.state.dosage}
/>
</View>
<View style={styles.dosageContainer}>
<Text style={{flex: 1, marginTop: 100, marginLeft: 30}}>
Select Measurement:
</Text>
<Picker
style={styles.picker}
selectedValue={this.state.selectedMeasurement}
onValueChange={(itemValue, itemIndex) =>
this.setMeasurement(itemValue)
}>
<Picker.Item label="mg" value="mg" />
<Picker.Item label="g" value="g" />
<Picker.Item label="ml" value="ml" />
</Picker>
</View>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(timesDaily) => this.setTimesDaily(timesDaily)}
placeholder="Times daily"
value={this.state.timesDaily}
/>
</View>
<TextInput
style={styles.inputText}
onChangeText={(prescriber) => this.setPrescriber(prescriber)}
placeholder="Prescriber"
value={this.state.prescriber}
/>
<TextInput
style={styles.inputText}
onChangeText={(diagnoses) => this.setDiagnoses(diagnoses)}
placeholder="For diagnoses"
value={this.state.forDiagnoses}
/>
<TextInput
style={styles.inputText}
onChangeText={(instructions) => this.setInstructions(instructions)}
placeholder="Instructions"
value={this.state.instructions}
/>
<TouchableOpacity
style={this.isFormValid() ? styles.validButton : styles.invalidButton}
disabled={!Boolean(this.state.name && this.state.dosage && this.state.timesDaily)}
onPress={() => {
this.props.navigation.goBack()
this.props.addMedication(this.state.name, this.state.dosage,
this.state.selectedMeasurement, this.state.timesDaily)
}}
>
<Text style={{color: 'white'}}>Add Medication</Text>
</TouchableOpacity>
</View>
)
}
}
You can pass the state value but I think you cannot pass the addMedication method just like this.
Could you please try passing an arrow function that uses the setState method?
For example:
<Stack.Screen name="Add New Medication">
{(props) => <AddMedication {...props} addMedication={(name, dosage, measurement, timesDaily)=> {this.addMedication(name, dosage, measurement, timesDaily)}} />}
</Stack.Screen>

error in passing data through navigation in react native

I'm new to react native world and I'm trying to integrate a calendar with a time slot picker, so I'm trying to pass the selected date from the calendar to the slot picker page but I'm having this Error when I press on a date in the calendar and I couldn't fix it.
TypeError: undefined is not an object (evaluating 'navigation.navigate')
This is my calendar function:
const RequestMeeting = ({ navigation }) => {
const [isModalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
return (
<View style={{ margin: 100, }}>
<Button title="Show modal" onPress={toggleModal} />
<Modal isVisible={isModalVisible} avoidKeyboard={true} scrollHorizontal={true} propagateSwipe={true}>
<ScrollView>
<View style={{ margin: 50, backgroundColor: 'gray', borderRadius: 20, padding: 20, margin: 20 }}>
<Text style={styles.heading}>Request to Buy/Rent</Text>
<View style={{ paddingBottom: 10 }}></View>
<View >
<Calendar
onDayPress={(day) => navigation.navigate("Slot", { bookingDate: day })}
style={styles.calendar}
hideExtraDays
theme={{
selectedDayBackgroundColor: 'green',
todayTextColor: 'green',
arrowColor: 'green',
}}
/>
</View>
<Button
buttonStyle={styles.register}
title="Send Buy/Rent request"
/>
<Button
buttonStyle={styles.cancelbtn}
title="Cancel"
onPress={toggleModal}
/>
</View>
</ScrollView>
</Modal>
</View>
);
};
And this is my time slot picker function:
const jsonData = {
"slots": {
"slot1": "9:00am to 9:30am",
"slot2": "9:30am to 10:00am",
"slot3": "10:00am to 10:30am",
"slot4": "10:30am to 11:00am",
"slot5": "11:00am to 11:30am",
"slot6": "11:30am to 12:00pm"
}
}
const Slot = ({ navigation }) => {
const onPressBack = () => {
const { goBack } = navigation
goBack()
}
const slots = jsonData.slots
const slotsarr = Object.keys(slots).map(function (k) {
return (
<View key={k} style={{ margin: 5 }}>
<TouchableOpacity >
<Text>{slots[k]}</Text>
</TouchableOpacity>
</View>)
});
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<View >
<TouchableOpacity onPress={() => onPressBack()}><Text >Back</Text></TouchableOpacity>
<Text ></Text>
<Text ></Text>
</View>
{ slotsarr}
</View>
);
}
This error means that wherever you are rendering RequestMeeting or Slot (whichever one has the error) it's not getting the navigation prop. If it is rendered as a Screen then it will get the prop from the Navigator. If it's not a top-level screen then you need to pass down the prop from a parent or access it with the useNavigation hook.
Docs: Access the navigation prop from any component

Preventing state item in all components from changing with useContext()?

I'm trying to control the state of 2 components use useContext() in React-Native. I have a flatmap of cards that render on a screen. Each card has a press-able 'interested' icon. If I click on a card, it shows the details of the card and also the press-able 'interested' icon. Both should share the same state of being pressed and also send a 'interested bool to the backend.
Right now, if I press 'interested' on one card, the all get pressed. Same with the inside icon of the details page. Obviously the 'interested' state in the Context Provider is to broad and changing all of them. How can I filter out the state change?
Here is the card component that gets rendered from a flatlist:
import React, { useState, useEffect, useContext } from 'react';
import { Image, View, Text, TouchableOpacity } from 'react-native';
import { localDate } from 'utils/formatDate';
import PropTypes from 'prop-types';
import { ConcertContext } from '../../../context/ConcertContextProvider';
import LocationIcon from '../../../assets/images/locationIcon.svg';
import InterestedFilledIcon from '../../../assets/images/interested-filled.svg';
import InterestedEmptyIcon from '../../../assets/images/interested-empty.svg';
import ShareIcon from '../../../assets/images/share.svg';
import styles from './styles';
export default function ConcertCard({
gotoConcertPage,
artist,
cover,
concertCity,
scheduledAt,
description,
concertObj,
}) {
const [clickInterest, setClickInterest] = useState(concertObj.is_interested);
const { interested, setInterested, concertInterest } = useContext(ConcertContext);
const handleInterest = () => {
setInterested(prevState => !prevState);
concertInterest(concertObj);
};
useEffect(() => {
setClickInterest(interested);
}, [interested]);
return (
<TouchableOpacity onPress={() => gotoConcertPage(concertObj)}>
<View style={styles.card}>
<View style={styles.cardContent}>
<View style={styles.cropped}>
<Image style={styles.image} source={{ url: cover.url }} />
</View>
<View style={styles.textWrapper}>
<Text style={styles.date}>{localDate(scheduledAt, 'MMM D, h:mm A z')}</Text>
<View style={styles.locationWrapper}>
<LocationIcon style={styles.locationIcon} />
<Text style={styles.location}>{concertCity.name}</Text>
<Text style={styles.location}>{concertCity.address}</Text>
</View>
<Text style={styles.name}>{artist.name}</Text>
<Text style={styles.description}>{description}</Text>
</View>
<View style={styles.border} />
</View>
<View style={styles.icons}>
<View style={styles.sharedIcon}>
<ShareIcon />
</View>
{!clickInterest ? (
<InterestedEmptyIcon onPress={handleInterest} />
) : (
<InterestedFilledIcon onPress={handleInterest} />
)}
</View>
</View>
</TouchableOpacity>
);
}
ConcertCard.propTypes = {
gotoConcertPage: PropTypes.func,
artist: PropTypes.object,
cover: PropTypes.object,
concertCity: PropTypes.object,
scheduledAt: PropTypes.string,
description: PropTypes.string,
concertObj: PropTypes.object,
};
Here is the card details page:
import React, { useState, useEffect, useContext } from 'react';
import { Text, View, Image, ImageBackground, ScrollView, FlatList } from 'react-native';
import PropTypes from 'prop-types';
import Button from 'components/button';
import { localDate } from 'utils/formatDate';
import { ConcertContext } from '../../context/ConcertContextProvider';
import LocationIcon from '../../assets/images/locationIconTwo.svg';
import LittleFriendIcon from '../../assets/images/little-friend.svg';
import Star from '../../assets/images/Star.svg';
import QuestionMarkIcon from '../../assets/images/question-mark.svg';
import ShareIcon from '../../assets/images/ShareIconLarge.svg';
import styles from './concertStyles';
export default function ConcertPageScreen({ navigation, route }) {
const {
concertObj,
name,
artist,
scheduled_at,
interests,
concert_city,
other_cities,
description,
ticket_base_price,
} = route.params;
const { interested, setInterested, concertInterest } = useContext(ConcertContext);
const formatLocation = city => {
return city.slice(0, city.length - 5);
};
const handleInterest = () => {
setInterested(prevState => !prevState);
concertInterest(concertObj);
};
const buyTicket = concertObj => {
console.log('Buy ticked: ', concertObj.id);
};
return (
<>
<View style={styles.wrapper}>
<ImageBackground
style={styles.imageBackground}
imageStyle={{ opacity: 0.3 }}
source={{ url: artist.media }}
/>
<ScrollView vertical>
<View style={styles.headerWrapper}>
<Text style={styles.headerTitle}>{name}</Text>
<Text style={styles.smallText}>{artist.name}</Text>
<Text style={styles.date}>{localDate(scheduled_at, 'MMM D, h:mm A z')}</Text>
<View style={styles.locationWrapper}>
<LocationIcon style={styles.locationIcon} />
<Text style={styles.location}>{concert_city.name}</Text>
<Text style={styles.location}>{concert_city.address}</Text>
</View>
<Text style={styles.description}>{description}</Text>
<View style={styles.interestedWrapper}>
<LittleFriendIcon style={styles.littleMan} />
<Text style={styles.interested}>{interests} Interested</Text>
</View>
<View
style={{
borderTopColor: '#DADADA',
borderTopWidth: 0.2,
borderStyle: 'solid',
alignSelf: 'center',
height: 5,
marginTop: 32,
marginBottom: 28.5,
}}
/>
<View style={styles.tableWrapper}>
<View style={styles.tableHeaderWrapper}>
<Text style={styles.headerTitle}>DATES</Text>
<Text style={styles.headerTitle}>LOCATIONS</Text>
</View>
<View>
<FlatList
data={other_cities}
initialNumToRender={1}
renderItem={({ item }) => (
<View style={styles.tableItemsWrapper}>
<Text style={styles.dateItem}>
{localDate(item.date, 'MMM DD - h:mm A z')}
</Text>
<Text style={styles.locationItem}>{formatLocation(item.city)}</Text>
</View>
)}
concertCityId={item => `item${item.concert_city_id}`}
concertScheduleId={item => `item${item.concert_schedule_id}`}
/>
</View>
</View>
<View style={styles.iconWrapper}>
<View style={{ backgroundColor: '#292929', width: 44, height: 44, borderRadius: 30 }}>
<ShareIcon style={styles.shareIcon} />
</View>
{!interested ? (
<View
style={{ backgroundColor: '#292929', width: 44, height: 44, borderRadius: 30 }}>
<Star style={styles.starIcon} onPress={handleInterest} />
</View>
) : (
<View
style={{ backgroundColor: '#007AFF', width: 44, height: 44, borderRadius: 30 }}>
<Star style={styles.starIcon} onPress={handleInterest} />
</View>
)}
<Image style={styles.roundAvatar} source={{ url: artist.media }} />
</View>
<View style={styles.iconWrapper}>
<Text style={styles.shareIconText}>Share</Text>
<Text style={styles.interestedIconText}>I'm Interested</Text>
<Text style={styles.artistIconText}>Add Artist</Text>
</View>
<View style={styles.ticketWrapper}>
<Text style={styles.ticketPrice}>TICKET PRICES</Text>
<QuestionMarkIcon style={styles.ticketPrice} />
</View>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text style={styles.ticketLocation}>In-location</Text>
<Text style={styles.ticketLocation}>$ {ticket_base_price}</Text>
</View>
<View
style={{
borderTopColor: '#DADADA',
borderTopWidth: 0.5,
borderStyle: 'solid',
height: 20,
marginTop: 32,
marginBottom: 28.5,
}}
/>
<View style={styles.footerWrapper}>
<Text style={styles.headerTitle}>TICKET GUIDE</Text>
<Text style={styles.ticketDescription}>
This ticket is for a livestream concert. Sign In at www.colortv.me on your browser
to watch on our TV or laptop. On the go? Watch from the COLOR TV mobile app.
</Text>
</View>
</View>
<Button
rightIcon={false}
text="Buy Ticket"
style={styles.button}
onPress={() => buyTicket(concertObj)}
/>
</ScrollView>
</View>
</>
);
}
ConcertPageScreen.propTypes = {
navigation: PropTypes.object,
route: PropTypes.object,
};
and here is the Context Provider:
import React, { createContext, useState } from 'react';
import { concertInterestApi } from 'utils/apiRoutes';
import useFetcher from 'hooks/useFetcher';
import parseError from '../utils/parseError';
export const ConcertContext = createContext(null);
const ConcertContextProvider = ({ children }) => {
const { isLoading, error, fetcher } = useFetcher();
const [interested, setInterested] = useState([]);
const concertInterest = async concertObj => {
try {
await fetcher({
url: concertInterestApi(concertObj.id),
method: concertObj.is_interested ? 'DELETE' : 'POST',
});
} catch ({ response }) {
throw parseError(response);
}
};
return (
<ConcertContext.Provider value={{ interested, setInterested, concertInterest }}>
{children}
</ConcertContext.Provider>
);
};
export default ConcertContextProvider;
Perhaps I'm not wiring this up correctly at all and any suggestions would be welcome to manage state.
You are confused about the shape of your own context. In your Provider, interested is an array (I'm not sure of what) and setInterested is a function to replace that array. With that in mind, hopefully you can see the problem with this:
const { interested, setInterested, concertInterest } = useContext(ConcertContext);
const handleInterest = () => {
setInterested(prevState => !prevState);
concertInterest(concertObj);
};
You are treating interested as a boolean when it is an array. I think it's all of the concerts that this user is interested it? Or perhaps an array of all userIds who are interested in this concert? Or perhaps useState([]) is a mistake and it was always meant to be a boolean?
Either way, I would recommend moving the shared logic from the ConcertCard and ConcertPageScreen into a custom hook that consumes your context and return an onClickInterested handler function. Your hook can take the concert id and/or user id as an argument.

React Native: Keyboard keeps closing on key press when typing in TextInput

I have a functional component Login Screen and have 4 Input Fields in them, along with a login button.
Here is the Full Code for my component Screen:
export default function Login() {
//Configs
const navigation = useNavigation();
const orientation = useDeviceOrientation();
const { colors, dark } = useTheme();
const InputTheme = {
colors: {
placeholder: colors.accent,
primary: colors.accent,
error: "red",
},
};
/** State Codes */
//States
const [login, setLogin] = useState({
email: "",
password: "",
licenseKey: "",
deviceName: "",
});
const [loading, setLoading] = useState(false);
const [secureEntry, setSecureEntry] = useState(true);
//Errors
const [errorEmail, setEmailError] = useState(false);
const [errorPWD, setPWDError] = useState(false);
const [errorLicense, setLicenseError] = useState(false);
const [errorDevice, setDeviceError] = useState(false);
//Error Messages
const [messageEmail, setEmailMessage] = useState("Looks Good");
const [messagePWD, setPWDMessage] = useState("All Good");
async function VerifyInputs() {
var pattern = /^[a-zA-Z0-9\-_]+(\.[a-zA-Z0-9\-_]+)*#[a-z0-9]+(\-[a-z0-9]+)*(\.[a-z0-9]+(\-[a-z0-9]+)*)*\.[a-z]{2,4}$/;
if (login.email == "") {
//Email cannot be empty
setEmailMessage("Email cannot be Blank!");
setEmailError(true);
return;
} else if (login.email != "" && !pattern.test(login.email)) {
//Email is not valid
setEmailMessage("This is not a valid email address!");
setEmailError(true);
return;
} else {
console.log("resolved email");
setEmailMessage("");
setEmailError(false);
}
if (login.password == "") {
//Password cannot be empty
setPWDMessage("Password cannot be Empty!");
setPWDError(true);
return;
} else if (login.password.length < 5) {
//Password must be minimum 5 characters.
setPWDMessage("Password must be of minimum 5 characters!");
setPWDError(true);
return;
} else {
console.log("resolved password");
setPWDMessage("");
setPWDError(false);
}
if (login.licenseKey == "") {
//License Key can't be Empty
setLicenseError(true);
return;
} else {
console.log("License resolved");
setLicenseError(false);
}
if (login.deviceName == "") {
//Device Name can't be empty as well
setDeviceError(true);
return;
} else {
console.log("Device name resolved");
setDeviceError(false);
}
Toast.show("Validation Successful");
}
function MobileContent() {
console.log("mobile_content rerendered");
return (
<View style={{ flex: 1, backgroundColor: colors.accent }}>
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}></View>
<View style={{ flex: 3, justifyContent: "center" }}>
{/**Main Content */}
<View style={[styles.content, { backgroundColor: colors.primary }]}>
<View style={{ flex: 1 }}>
{/**For Header */}
<Header />
</View>
<View style={{ flex: 5 }}>
{/**For Content */}
<ScrollView style={{ flex: 1 }}>
<LoginContent />
</ScrollView>
</View>
<View style={{ flex: 1 }}>
{/**For Footer */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function TabContent() {
console.log("tab_content rerendered");
return (
<View
style={{
flex: 1,
backgroundColor: colors.accent,
flexDirection: orientation.landscape ? "row" : "column",
}}>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}></View>
<View style={{ flex: 1.5, justifyContent: "center" }}>
{/**Main Content */}
<View style={[styles.content, { backgroundColor: colors.primary }]}>
{/**Header Wrapper */}
<View style={{ justifyContent: "center" }}>
{/**Header Title */}
<Header />
</View>
{/**Content Wrapper */}
<LoginContent />
{/**Footer Wrapper */}
<View style={{ justifyContent: "center" }}>
{/** Login Button */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function Header() {
console.log("header_component rerendered");
return (
<View style={{ margin: "5%" }}>
<Title>Welcome User</Title>
<Subheading>Please Sign In to Continue..</Subheading>
</View>
);
}
function Footer() {
console.log("footer_component rerendered");
return (
<View style={{ margin: isTablet ? "5%" : "3.5%" }}>
<Button
title="Login"
loading={false}
ViewComponent={LinearGradient}
containerStyle={{ maxWidth: isTablet ? "45%" : "100%" }}
buttonStyle={{ height: 50, borderRadius: 10 }}
linearGradientProps={{
colors: [colors.accent, colors.accentLight],
start: { x: 1, y: 1 },
end: { x: 1, y: 0 },
}}
onPress={() => {
VerifyInputs();
//navigation.navigate("verify");
}}
/>
</View>
);
}
function LoginContent() {
console.log("login_component rerendered");
return (
<View style={{ margin: "3%" }}>
{/**Login & Email Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Email"
value={login.email}
error={errorEmail}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, email: text })}
/>
{errorEmail ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messageEmail}
</HelperText>
) : null}
</View>
<View style={styles.input}>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TextInput
mode="outlined"
label="Password"
value={login.password}
error={errorPWD}
theme={InputTheme}
secureTextEntry={secureEntry}
style={{ flex: 1, marginBottom: 5, marginEnd: isTablet ? 15 : 5 }}
onChangeText={(text) => setLogin({ ...login, password: text })}
/>
<Button
icon={
<Icon
name={secureEntry ? "eye-off-outline" : "eye-outline"}
size={30}
color={colors.primary}
/>
}
buttonStyle={{
width: 55,
aspectRatio: 1,
backgroundColor: colors.accent,
borderRadius: 10,
}}
containerStyle={{ marginStart: 5 }}
onPress={async () => setSecureEntry(!secureEntry)}
/>
</View>
{errorPWD ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messagePWD}
</HelperText>
) : null}
</View>
</View>
{/**License & Device Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="License Key"
value={login.licenseKey}
error={errorLicense}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, licenseKey: text })}
/>
{errorLicense ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
License Key cannot be Empty!
</HelperText>
) : null}
</View>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Device Name"
value={login.deviceName}
error={errorDevice}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, deviceName: text })}
/>
{errorDevice ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
Device Name cannot be empty
</HelperText>
) : null}
</View>
</View>
</View>
);
}
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle={"dark-content"} backgroundColor={colors.accent} />
{isTablet ? <TabContent /> : <MobileContent />}
</SafeAreaView>
);
}
As you can see by looking at the code.. my Login component's rendering responsive component layouts based on device type being phone or tablet, the following components MobileContent or TabContent.
MobileContent functional component wraps my main content in a ScrollView & TabContent functional component doesn't need a scrollview but has responsive scaling views.
Both of these parent components display my common components, Header,LoginContent & Footer.
My Header component just displays a standard title & subheading. My LoginContent component has all the TextInput fields in them with validation logic setup as well. My Footer component has the Submit/Login button. That's All.
So we can summarize the components tree for screen as:
Login Screen/Parent Component => Mobile Content/Tab Content => Header, LoginContent & Footer (Common Components)
Alright, so now what is the issue? the major issue for me lies for TextInputs in LoginContent component, but I assume the underlying issue is applicable for entire Login Screen component.
The ISSUE: When I click on TextInput fields, the input gets focus and Keyboard appears. Everything is fine till this point. As soon as I type even a single letter, single key press on keyboard.. The Keyboard closes immediately and the text input is lost focus.
Why it could be happening? I believe this might be the classic 'React Component Re-render' problem, which causes by TextInput to be re-rendered when state is updated by the onChangeText for the TextInput and hence it loses focus & that's why the Keyboard closes.
So, I hope to resolve atleast first issue from these two issues.
Issue 1: How do I prevent the Keyboard from constantly closing when I try to type something in any of the TextInput fields.
Issue 2: How can I better optimize my Parent & Children components rendering on every state update using the any of these two React Hooks useCallback() and useMemo()?
I've read the documentation for these two hooks useCallback & useMemo multiple times and still haven't grasped the concept of these hooks. All posted examples deal with a Counter Exmaple optimized using useCallback or useMemo but I'm not working with Counters here in my Screen.
I need a more practical exmaple of useCallback() & useMemo() in screen components. Perhaps an implementation of these two hooks in my current Login Screen component will help me understand & grasp the concept better.
Like I mentioned, solving Issue 1 is my highest priority atm, but I know a solution for Issue 2 will help me in the long run as well. It will be very helpful if you can resolve both of my issues here. Thanks for helping.

How to pass form data to another page in react native?

I've created a login page like this:
class Login extends Component {
render() {
const { navigate } = this.props.navigation
return (
<View style={{ flex: 1 }}>
<View style={styles.container}>
<View style={styles.container1}>
<TextInput
style={{ width: 190, color: 'white' }}
placeholder="User Name"
placeholderTextColor="#f9f9f9"
underlineColorAndroid="#f9f9f9"
/>
<TextInput
placeholder="Password"
secureTextEntry
returnKeyType="go"
ref={input => (this.passwordInput = input)}
style={{ width: 190, color: 'white' }}
placeholderTextColor="#f9f9f9"
underlineColorAndroid="#f9f9f9"
/>
<TouchableOpacity style={{ top: 10 }}>
<Button
color="#314561"
onPress={() => navigate('HomePage')}
title="Login"
/>
</TouchableOpacity>
</View>
</View>
</View>
)
}
}
export default Login
Now I need to pass the username to the home page. I've referred a number of resources and didn't got any solutions. How can I pass the username to home page?
First save your input value to some variables using onChangeText
<TextInput
value= {this.state.userName}
onChangeText = {(text)=>{
this.setState({userName:text});
}
/>
Then you can pass the value ,
<Button
onPress={() => navigate('HomePage',{"userName":this.state.userName})} // you can pass objects
title="Login"
/>
Do the following changes :
In Login component :
Username Field
<TextInput
style={{width:190,color:'white'}}
placeholder="User Name"
placeholderTextColor="#f9f9f9"
underlineColorAndroid='#f9f9f9'
onChangeText=
{(username)=>this.setState({username})}
/>
Button :
<TouchableOpacity style={{top:10}}>
<Button
color="#314561"
onPress={() => navigate('HomePage'), { username: this.state.username }}
title="Login"/>
</TouchableOpacity>
In Home component:
e.g. render method
render(){
const {state} = this.props.navigation;
console.og(state.params.username)
}
Update :
In login constructor,initialise state
constructor(){
super();
this.state = {};
}
class Login extends Component {
constructor(props) {
super(props);
this.state = {
userName:"",
password:""
};
}
updateUserName = (name) =>{
this.setState({
userName:name,
})
}
updatePwd = (pwd) =>{
this.setState({
password:pwd,
})
}
render() {
const { navigate } = this.props.navigation
return (
<View style={{ flex: 1 }}>
<View style={styles.container}>
<View style={styles.container1}>
<TextInput
style={{ width: 190, color: 'white' }}
placeholder="User Name"
placeholderTextColor="#f9f9f9"
underlineColorAndroid="#f9f9f9"
onChangeText={(name) => this.updateUserName(name)}
value={this.state.userName}
/>
<TextInput
placeholder="Password"
secureTextEntry
returnKeyType="go"
ref={input => (this.passwordInput = input)}
style={{ width: 190, color: 'white' }}
placeholderTextColor="#f9f9f9"
underlineColorAndroid="#f9f9f9"
onChangeText={(pwd) => this.updatePwd(pwd)}
value={this.state.password}
/>
<TouchableOpacity style={{ top: 10 }}>
<Button
color="#314561"
onPress={() => navigate('HomePage',{userName:this.state.userName})}
title="Login"
/>
</TouchableOpacity>
</View>
</View>
</View>
)
}
}
export default Login
file : homePage.js
constructor(props) {
super(props);
const { params } = this.props.navigation.state;
var data = params.userName;
this.state = {
userName : data
};
}

Resources