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;
Solution 1:
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}
/>
...
}
...
Solution 2:
In React Native 0.43: (Maybe later than 0.43 is OK.)
_handlePress(event) {
var username= this.refs.username._lastNativeText;
Solution 3:
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
}
}
/>
Solution 4:
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>
)
}
}
Solution 5:
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