React Native TextInput save to const - javascript

Summary
I have a react native functional component where I collect a value from the user in TextInput and then need to pass that value to a function when a button is pressed. I know how to do this in a react native class component with state, however I'm trying to use a functional component.
I'm close to figuring it out but I'm just missing something. The code I have so far is below.
saveUserInput handles saves the text from the user and returns input. When I pass saveUserInput into forgotPassword, which is my function that sends userInput to my backend to reset password, saveUserInput is defined as the function as opposed to the value it returns. How can make this work as a functional component?
Code
export default (ForgotPasswordScreen = () => {
const saveUserInput = userInput => {
const input = userInput;
return input;
};
return (
<View style={styles.container}>
<Text style={styles.headerText}>Forgot Password</Text>
<Text style={styles.forgotText}>
Enter your username or email address below to reset your password
</Text>
<TextInput
onChangeText={userInput => saveUserInput(userInput)}
placeHolder={"username or email"}
/>
<Text
style={styles.buttonText}
onPress={saveUserInput => forgotPassword(saveUserInput)}
>
Forgot Password Button
</Text>
</View>
);
});

export default (ForgotPasswordScreen = () => {
let input = '';
const saveUserInput = userInput => {
input = userInput;
};
return (
<View style={styles.container}>
<Text style={styles.headerText}>Forgot Password</Text>
<Text style={styles.forgotText}>
Enter your username or email address below to reset your password
</Text>
<TextInput
onChangeText={userInput => saveUserInput(userInput)}
placeHolder={"username or email"}
/>
<Text
style={styles.buttonText}
onPress={() => forgotPassword(input)}
>
Forgot Password Button
</Text>
</View>
);
});
This should do the trick without using hooks. Pull out the input variable to be in scope for all other components to use.
But life could be much easier using useState hooks.

Related

Reusing Component State issue - State always retained for last reference loaded

I tried creating a reusable component in React. Which has a textInput and secure text entry handled in the state of the reusable component. But the state is not getting maintained differently when reusing always the last state is updated,
Issue: If i call the reusable const two times on a single screen or on the next screen in stack. The toggle for secure entry keeps changing for the last field loaded and earlier loaded fields state is lost.
i.e., when i click on toggle of Password, text change from hidden to visible or vice-versa happens for Confirm password field.
This is how i call
<View style={styles.inputContainerView}>
<InputTextFieldView
enteredText={passwordEntered}
setEnteredText={setPasswordEntered}
title={Constants.registerPasswordPlaceholder} icon={lockIcon}
isSecureEntry={true}
placeholder={Constants.registerPasswordPlaceholder} />
</View>
<View style={styles.inputContainerView}>
<InputTextFieldView
enteredText={confirmPasswordEntered}
setEnteredText={setConfirmPasswordEntered}
title={Constants.registerConfirmPasswordPlaceholder} icon={lockIcon}
isSecureEntry={true}
placeholder={Constants.registerConfirmPasswordPlaceholder} />
</View>
My component:
const InputTextFieldView = ({ enteredText, setEnteredText, title, icon, isSecureEntry, placeholder }) => {
const [isSecureEntryEnabled, setIsSecureEntryEnabled] = useState(isSecureEntry)
const eyeOpenIcon = require('../../../assets/visibility.png')
const eyeCloseIcon = require('../../../assets/close-eye.png')
useEffect(() => {
console.log('called')
}, [])
toggleSecureTextEntry = () => {
console.log('title', title)
setIsSecureEntryEnabled(!isSecureEntryEnabled)
}
return (
<View style={styles.fieldsContainerView}>
<Text style={styles.titleStyle}>{title}</Text>
<View style={[styles.fieldInputContainerView, {padding: Platform.OS === 'ios' ? 12 : 0}]}>
<Image source={icon} style={styles.fieldIconView} />
<TextInput secureTextEntry={isSecureEntryEnabled} style={{ width: isSecureEntry ? '75%' : '85%' }} onChange={() => setEnteredText()} value={enteredText} placeholder={placeholder} />
{isSecureEntry &&
<TouchableWithoutFeedback onPress={() => toggleSecureTextEntry()}>
<Image source={isSecureEntryEnabled ? eyeOpenIcon : eyeCloseIcon} style={styles.fieldIconView} />
</TouchableWithoutFeedback>
}
</View>
</View>
)
}
I'm guessing that you are using isSecureEntry as the hook to toggle the password fields? If so, it looks like you are passing the same state to both
the password field and the confirm password field. Right now, you essentially have one light switch that controls two different lamps. So you are going to want to have separate separate useState hooks for the password field and confirm password field. Then pass each one to the correct component.
const [passwordSecure, togglePasswordSecure] = useState(true);
const [confirmPasswordSecure, toggleConfirmPasswordSecure] = useState(true);
const togglePasswordField = () => {
togglePasswordSecure(!passwordSecure)
};
const toggleConfirmPasswordField = () => {
toggleConfirmPasswordSecure(!confirmPasswordSecure)
};
Issue was happening due to TouchableWithoutFeedback. Now used TouchableOpacity and it started to work. Not sure why but it may help someone

How to save TextInput with it's defaultValue if the user hasn't changed anything?

Okay so I hope this is easy, but I can't find anything about that on Google.
I have a details screen for a (cooking)receipe in my app. With the tap of a button the user can set a state isEditing, which then converts a heading into a text input. That heading displays {receipe.title} and I use the same value for the default value prop on the text input.
Once the user taps the edit button again, isEditing will be set to false and a update function will update the receipe in my Firebase database.
{!isEditing ? (
<Text style={styles.headingLarge}>{receipes.title}</Text>
):(
<TextInput
placeholder='Titel'
autoFocus={true}
defaultValue={receipes.title}
style={styles.headingLarge}
onChangeText={text => {
setPresentTitle(text);
}}/>
)}
It's all working, as long as the user actually changes something in the input. But the issue is that if a user doesn't change anything, onChangeText is never called and the database is updated with an empty string as it's title.
Is there a way to call the onChangeText when setting the defaultValue for this input (or another hack to set the setPresentTitle)?
Hey you can check this snack out, ive made it for you
This is the snack : https://snack.expo.dev/#gaurav1995/fascinated-donut
Hope it helps. feel free for doubts
import React,{ useState ,useEffect } from 'react';
import { StyleSheet, Text, TouchableOpacity, View ,TextInput ,Button } from 'react-native';
export default function App() {
const receipes = {
title:"Hey there"
}
const [isEditing, setEd] = useState(false)
const [text,setPresentTitle] = useState(receipes.title)
const toggleEdit = () => {
setEd(!isEditing)
}
useEffect(() => {
//update to firebase
//setFirebase(text)
},[text])
return (
<View>
{!isEditing ? (
<Text style={styles.headingLarge}>{text}</Text>
):(
<TextInput
placeholder='Titel'
autoFocus={true}
value={text}
style={styles.headingLarge}
onChangeText={text => {
setPresentTitle(text);
}}/>
)}
<Button title="Toggle Edit" onPress={toggleEdit} containerStyle={{marginTop:20}} />
</View>
)
}
const styles = StyleSheet.create({
container:{
flex:1,
padding:40
},
headingLarge:{
fontSize:40,
marginBottom:20
}
})

How to pass Button component's title into a function in React Native

I want to pass the title of a React Native Button component into a neighbouring function. I am using React Native functional components only for this application.
Here's the component. I would like to pass the title of the button pressed by the user, which will be either 'English' or 'Arabic', into the function submitLanguageSelection so that I can then save that value into useLocalStorage(), a custom hook I wrote to handle AsyncStorage, so that the next time the user uses the app, their language choice will be persisted, and they will not be shown the ChooseYourLanguageScreen again.
All help appreciated, thank you.
const ChooseYourLanguageScreen = ({ navigation }) => {
const [saveData, storedValue, errorMessage] = useLocalStorage();
const [userSelectedLanguage, setUserSelectedLanguage] = React.useState('');
const submitLanguageSelection = () => {
//TODO: receive params from onPress
//TODO: save the data locally
//TODO: navigate to welcome screen
};
return (
<View style={styles.container}>
{errorMessage ? <Text>{errorMessage}</Text> : null}
<Text style={styles.text}>This is the Choose Your Language Screen</Text>
<View style={styles.buttons}>
<View>
<Button
title={'English'}
onPress={() => submitLanguageSelection()}
/>
</View>
<View>
<Button title={'Arabic'} onPress={() => submitLanguageSelection()} />
</View>
</View>
</View>
);
};
You can simply pass it to the function
<Button title={'Arabic'} onPress={() => submitLanguageSelection('Arabic')} />
And access like below
const submitLanguageSelection = (language) => {
console.log(language);
};
Getting data from a sibling component is an anti-pattern.
The source of the knowledge of the language options is the ChooseYourLanguageScreen component (as seems from your snippet), so it should hold the list of available languages. Having that, you can just iterate through them and render the appropriate components:
<View style={styles.buttons}>
{languages.map((language) => (
<View key={language}>
<Button
title={language}
onPress={() => submitLanguageSelection(language)}
/>
</View>
))}
</View>

Function is not being called when state changes

This is my function for rendering items in a flatlist
renderItem = ({ item }) => {
var integer = Number(item.key)
return (
<View>
<Text style={styles.row}>
{item.text}
</Text>
<View style={{flexDirection:'row'}}>
{this.createButtonYes(integer)}
{this.createButtonNo(integer)}
{this.answer(this.state.buttonStates[integer])}
</View>
<Text >__</Text>
</View>
)
}
And the problem I am facing is the function this.answer is not being called when the state of buttonStates changes
answer = (val) => {
if(val){
return(
<Text style={{fontSize:20}}>YES</Text>
)
}else if(val==false){
return(
<Text style={{fontSize:20}}>NO</Text>
)
}else{
return(
<Text style={{fontSize:20}}>Not Answered</Text>
)
}
}
I assumed that every time the state changes the function would be called but that does not seem to be the case, so does anyone have a solution? What I want is whenever the buttons are pressed the state will change and then this.answer will take the changed state and display what it has to accordingly.
Thanks
EDIT:
Code for the button:
buttonYesHelp = num =>{
const newItems = [...this.state.buttonStates];
newItems[num] = true;
return newItems
}
createButtonYes = (num) => {
return(
<TouchableOpacity style={styles.buttonYes}
onPress =
{
()=> {{this.setState({ buttonStates:this.buttonYesHelp(num) })}}
}>
<Text style={styles.buttonTextStyle}>YES</Text>
</TouchableOpacity>
)
}
num is the index of the thing I want to change in the list
EDIT:
I have tried multiple different things but the problem I keep running into is that when I render the button I want it to react to a state variable but it never seems to change based on the state even when the state is changing.
For example, in this.answer I assumed that it would return the text based on the state of buttonStates but it seems to only account for the initial state and nothing after
I was able to achieve this in a different piece of code with identical syntax but for some reason this is not working

react-native: InputText activity firing TouchableHighlight onPress() events

I have the following react-native code where I am trying to build a custom form to gather user input. The form renders correctly with 3 input boxes and a Save button.
In the code below, the issue is that as soon as I start typing on the first TextInput field, the this.saveFormData() which is called only inside the TouchableHighlight button gets fired!
Why are the TextInput events conflicting with the TouchableHighlight ones? How do I fix the issue?
class NewScreen extends React.Component {
constructor(props) {
super(props);
this.state = { songTitle: null, chord: null, strumPattern: null };
}
saveFormData = () => {
console.log(this.state.songTitle);
() => navigate("Home");
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.row_cell_chord_songTitle}>
<Text style={styles.new_input_label}> Song Title </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ songTitle: text })}
value={this.state.songTitle}
/>
<Text style={styles.new_input_label}> Chords </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ chord: text })}
value={this.state.chord}
/>
<Text style={styles.new_input_label}> Strumming Pattern </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ strumPattern: text })}
value={this.state.strumPattern}
/>
</View>
<TouchableHighlight
style={styles.saveButton}
onPress={this.saveFormData()} // <-- typing on above Inputbox fires this function.
>
<Text style={styles.buttonText}>
<FontAwesome>{Icons.heart}</FontAwesome> Save
</Text>
</TouchableHighlight> */
</View>
</View>
</View>
);
}
}
You need to pass a function to onPress, currently you're invoking the function and passing whatever it returns. You just need to change it to:
onPress={this.saveFormData}

Categories