Get TextInput value from different component - react-native

I have 2 react native components in my app, one is a toolbar that has a "Done" button, pressed when a user is done filling a form.
The other is the form itself from where I need to get the data.
When the user clicks "Done" I send a post request with the parameters, but I can't find a neat way to get the data.
What is best practice for this?
My toolbar:
<TopToolbar text='Upload new item'
navigator={this.props.navigator} state={this.state} donePage={'true'}/>
In the toolbar component I have the done button:
<TouchableHighlight style={styles.done} onPress={() =>{this.state.text=this.props.state.data.price}} underlayColor='#4b50f8'>
<Image source={require('./Images/Path 264.png')}/>
</TouchableHighlight>
and one of the text inputs is:
<TextInput placeholder='Price*' style={styles.text} onChangeText={(text) => { this.state.data.price = text }}></TextInput>

Use state. You need to bind the view to the model => (state). Please add your code for a better guide.
Each time that you press and new character need be saved in your state using onChangeText
Example:
class UselessTextInput extends Component {
constructor(props) {
super(props);
this.state = { text: 'Useless Placeholder' };
}
render() {
return (
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
);
}
}
When you press in Done button. The TextInput value will be stored in this.state.text
For more info: https://facebook.github.io/react-native/docs/textinput.html
I think your main problem is that you need to read more about the states in the react documentation
https://facebook.github.io/react-native/docs/state.html
When you needs set the state. You should use setState not this.state.data.price = text. The state is a object with multiple keys y your needs modify one internal key inside data you need modify all data key and replace it.
Example:
In your constructor declare
this.state = { data: {price: 10, name: xxxx} };
if need modify data you should do something like.
var dataM = this.state.data;
dataM.price = 200
this.setState({ data: dataM});

Related

React-Native TextInput for registering a user Why is the typed text is not displaying or being stored into the setInput object?

Hello I am trying to navigate creating a text input on React-Native that lets the user enter their email password and name and stores it in the object. But it is not working how I expected and I am not sure where I have gone wrong. I have looked at similar projects online but most are done with React not react-natie and even still when i try their implementation it still doesnt fix the text not displaying as i type or allowing it to be store when the user presses the register button.
import { Text, View, TextInput, Button, StyleSheet} from 'react-native';
import {useState} from 'react';
export default function Home() {
const [input, setInput] = useState({
fullName:"",
email:"",
password: "",
});
const inputHandler = (e) => {
let name = e.target.fullName
let value = e.target.value;
setInput({
...input,
[name]: value,
});
};
const registerUser = (e) => {
e.preventDefault();
console.log(input)
setInput({
fullName:"",
email: "",
password:"",
});
};
return (
<View >
<Text style={styles.welcome}>
Welcome! Please Register Below
</Text>
<TextInput style={styles.input} placeholder="Name" value={input.fullName} onChangeText={inputHandler}/>
<TextInput style={styles.input} placeholder="Email" value={input.email} onChangeText={inputHandler}/>
<TextInput style={styles.input} placeholder="Password" value={input.password} onChangeText={inputHandler} />
<View style={styles.button}>
<Button title="Register" onPress={registerUser} />
</View>
<View style={styles.button}>
<Button title="Already Registered? Click here to login" onPress={()=> register()} />
</View>
</View>
);
}
const styles = StyleSheet.create({
welcome:{
padding:10
},
input: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
borderColor:'black',
borderWidth: 2,
margin:3
},
button:{
margin:5
}
});```
I have tried this.input.fullName in the value prop but that give me an error as that is not the way i defined it with my handlers. I also could go back to just using seperate states for each input like [name,setName] [password,setPassword] ect... but I would really like to understand where my knowledge is lacking for utilizing TextInput to pass user information and storing it.
From looking through similar stackoverflow questions I also tried changing my onChangeText to this
`onChangeText={(t) =>inputHandler(t)}`
but that also doesnt solve it
Thanks!
Text is not displayed, because you react on changes, but not change state properly. onTextChanges callback return to you only text (as string), not as Event. If you need track Event you can use onChange callback.
But, I recommend to you write your logic as clean and simple as possible.
Firstly, you should separate inputHandler to independent text changes functions, because it easily to manage for now in your case. For example:
const onNameChanges = (text) => {
setInput(prev => ({
...prev,
fullName: text
}))
}
And then just assign it to props of your TextInput
<TextInput style={styles.input} placeholder="Name" value={input.fullName} onChangeText={onNameChanges}/>
That's it. You code works as expected. I prepared working example for you here
https://snack.expo.dev/BkQi-kXr-8

React Native Flatlist dynamic style

I'm trying to make buttons out of react native FlatList items, that means when I click on them they change color.
This is the function that gets rendered by the renderItem prop:
renderRows(item, index) {
return (
<TouchableOpacity
key={index}
style={[styles.item, this.calculatedSize()]}
onPress={() => this.onPressImage(index)}
>
<Image
style={[styles.picture]}
source={{ uri: item.uri }}
/>
<View
style={[
styles.imageTextContainer,
{
backgroundColor:
_.indexOf(this.active, index) === -1
? 'rgba(0,0,0,0.2)'
: 'rgba(26, 211, 132, 0.7)',
},
]}
>
<Text style={styles.imageText}>{item.title}</Text>
</View>
</TouchableOpacity>
)
}
oh yeah and im using loadash to get the index.
The function "onPressImage(index)" works fine, in "this.active" (array) I always have the positions(integer) of the elements I would like to change color,
however nothing happens, the only thing you can see is the response by the touchableOpacity. What am I doing wrong ?
Like Andrew said, you need to trigger a re-render, usually by updating state.
However, if the items don't depend on anything outside the FlatList, I would recommend creating a component (preferably a PureComponent if possible) for the items themselves, and updating their state upon press. This way it will only re-render each list item individually if there is a change instead of the parent component.
Thanks, updating the state was a little bit difficult, the items array I've used has been declared outside the class component, thus only using an "active" array with indices that should change color in the state wasn't enough, I had to map the items array in the state like so:
state = {
items: items.map(e => ({
...e,
active: false,
}))
}
then I could manipulate the active state of the element I wanted to change color like this:
onPressItem(index) {
const { items } = this.state
const newItems = [...this.state.items]
if (items[index].active) {
newItems[index].active = false
} else {
newItems[index].active = true
}
this.setState({ items: newItems })
}
and change the color like so:
style={{
backgroundColor: item.active
? 'rgba(26, 211, 132, 0.7)'
: 'rgba(0,0,0,0.2)',
}}

When and how often does the component re-render as users type information in a form?

Let’s say there is a code below where I listen to the event with onChangeText inside MyTextInput class. I update the state in onChangeText, which means the component will re-render.
When and how often does the component re-render as users type information in a form? I’m asking because I don’t believe it’s a good practice to re-render unnecessarily when the users are still in the middle of typing information.
export default class MyTextInput extends Component {
this.state = { text: '' };
render() {
return (
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
);
}
}
The entire component doesn't re-render just the text box, read this for more information regarding setState and stopping multiple rendering https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60

How to make React Native TextInput keep text after screen change

I am making an app which contains a notes field which needs to keep its input after the screen changes, but it always resets after you leave the page. Here is my constructor for the state:
this.state = {text: ""};
And my textinput declaration:
<TextInput
style={{
height: 200,
width: 250,
fontSize: 15,
backgroundColor: 'white',
}}
editable = {true}
multiline = {true}
numberofLines = {4}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
I've been trying to find a way to set the state to a variable that doesn't get reinitialized on opening the page up but have no luck so far. Any advice would be appreciated!
Use AsyncStorage to persist the input value. For eg:
<TextInput
style={{
height: 200,
width: 250,
fontSize: 15,
backgroundColor: 'white',
}}
editable = {true}
multiline = {true}
numberofLines = {4}
onChangeText={(text) => {
this.setState({text});
AsyncStorage.setItem('inputKey', text); // Note: persist input
}}
value={this.state.text}
/>
Then inside componentDidMount you can check for the value and update state accordingly to reinitialise with old value.
componentDidMount() {
AsyncStorage.getItem('inputKey').then((value) => {
if (value !== null){
// saved input is available
this.setState({ text: value }); // Note: update state with last entered value
}
}).done();
}
It's because when you leave the page in certain type of navigation you trigger the "componentUnmount" and it get destroy and rebuild when you come back.
You have to store your data away from your component class. In an other class for example. A class with only one instance
...
let instance = null;
class OtherClass {
constructor() {
if(instance) {
return instance;
}
instance = this;
}
...
}
So when your user make an input save the content in that "OtherClass" and then each time you rebuild your parent component, you set the value with data previously store here.
Each time you initialize that class the content wont be erase because it will always take the previous instance.
Hope it help !

Is there a Cross platform clearButtonMode for Android with React Native

How should one implement the "X" to clear button in react native so that it works with Android as well as iOS. iOS has the text input option of "clearButtonMode" enum('never', 'while-editing', 'unless-editing', 'always').
To make it cross platform, do we need to just add an android conditional rendering of the clear button? Something like:
{Platform.OS === 'android' && <ClearTextButton />}
Seems a bit hacky so I am wondering if there is a cleaner method for this.
For your problem, you just need to create a simple button to handle the clear function of your input field and place it right next to your TextInput component to have the effect of clearButtonMode.
A naive implementation could be something like this:
Create these states in your main component constructor :
A state for the status of your TextInput (is it touched?, does it have text yet?)
A state for the actual value of your TextInput, set your TextInput's value to this state.
For example:
this.state = {
textInput1Status: 'untouched',
textInput1Value: '',
};
Create callback functions to set your states:
Create a callback function to set both your TextInput's value state and status state and assign it to the onChange prop of you TextInput.
For example:
<TextInput
onChangeText={(text) => this.onTextInput1Change(text)}
value={this.state.textInput1Value}
/>
...
onTextInput1Change(text) {
this.setState({
textInput1Status: 'touched',
textInput1Value: text
});
}
Create your own button using TouchableOpacity and handle the clear function.
For example:
<TouchableOpacity onPress={this.clearText}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableOpacity>
...
clearText() {
this.setState({
textInput1Status: 'untouched',
textInput1Value: '',
});
}
Handle the rendering of your "X" button:
For example:
renderClearButotn() {
if (this.state.textInput1Status == 'touched') {
return (
<TouchableOpacity onPress={this.clearText}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableOpacity>
);
} else {
return '';
}
}
...
render() {
return (
<TextInput
onChangeText={(text) => this.onTextInput1Change(text)}
value={this.state.textInput1Value}
/>
{this.renderClearButton()}
);
}
In this way your code will be independent from both iOS and Android. I hope this could help you!
There is another simple solution I found from this article. It works perfect for me in Android, and it is expected to give the same view and behavior in iOS also.
I had to modify the styles slightly to match with my UI
closeButtonParent: {
justifyContent: 'center',
alignItems: 'center',
borderTopRightRadius: 5,
borderBottomRightRadius: 5,
backgroundColor: "#cdcdcd",
width: 30,
},
Code credit goes to https://www.codevscolor.com/react-native-text-input-clear-button/ auther
This solution works ok but it's not the exact same effect than the clearButtonMode in iOS. The clearButtonMode won't dismiss the keyboard when clicked, and this solution for android will dispatch the Keyboard.dismiss event natively and there's no way to catch it, so the user needs to tap again on the input to get the keyboard back.