I'm building a simple form in React Native. What I'm trying to do is that when the value of the input field changes, I want to update the state (phone in this case). The value of the input field always equals the value of a state. However, when the value of the input field changes, the value of the state(phone) is not updated. Thanks in advance. Here is the code.
import React from 'react';
import { StyleSheet, TextInput, View } from 'react-native';
const styles = StyleSheet.create({
input: {
padding: 5,
borderColor: 'black',
borderWidth: 1,
},
});
export default class AddContactForm extends React.Component {
state = {
phone: 'sdfksd',
};
handlePhoneChange = (phone) => {
this.setState({
phone: '111',
});
};
render() {
return (
<View style={{ paddingTop: 40 }}>
<TextInput
style={styles.input}
value={this.state.phone}
onChangeText={this.handlePhoneChange}
keyboardType="numeric"
placeholder="Phone"
/>
</View>
);
}
}
UPDATED: Even though I set phone in handlePhoneChange, I still can update the text field to a different value apparently. That's inconsistent between the state and the text field.
onChangeText takes a callback.
So in your case pass the input to your function like this
onChangeText={ val => this.handlePhoneChange(val)}
Change your handle function like this.
handlePhoneChange = (phone) => {
this.setState({
phone: phone
})
}
Related
I am a bit new to react native and I have an issue I need help with
how do I build a text input in react native that has a placeholder that changes to a text view on top when clicked?
Similar to the screenshot below
empty text input field looks like this in its default state
text field with data entered
see the empty input text has a placeholder appearing in the middle of the input text field
see the second diagram, the place holder text is moved to the top of the input field once the user starts typing text into the input field
The easiest way is to use react-native-paper package with their text input:
import * as React from 'react';
import { TextInput } from 'react-native-paper';
const MyComponent = () => {
const [text, setText] = React.useState('');
return (
<TextInput
label="Email"
value={text}
onChangeText={text => setText(text)}
/>
);
};
export default MyComponent;
Result:
Here is what I use without any library, working example and if you want to add animation to the fields working example with animation
import React, { Component } from 'react';
import {
View,
StatusBar,
TextInput,
Text,
} from 'react-native';
class FloatingLabelInput extends Component {
state = {
isFocused: false,
};
handleFocus = () => this.setState({ isFocused: true });
handleBlur = () => this.setState({ isFocused: false });
render() {
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 18 : 0,
fontSize: !isFocused ? 20 : 14,
color: !isFocused ? '#aaa' : '#000',
};
return (
<View style={{ paddingTop: 18 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{ height: 26, fontSize: 20, color: '#000', borderBottomWidth: 1, borderBottomColor: '#555' }}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
);
}
}
export default class App extends Component {
state = {
value: '',
};
handleTextChange = (newText) => this.setState({ value: newText });
render() {
return (
<View style={{ flex: 1, padding: 30, backgroundColor: '#f5fcff' }}>
<StatusBar hidden />
<FloatingLabelInput
label="Email"
value={this.state.value}
onChangeText={this.handleTextChange}
/>
</View>
);
}
}
I have created a component called "CommonStyleGenerator", to generate simple style object with keys like height, width and bgColor. I have created a text fields in component and whenever text change in any of text field I am calling onStyleChange with changed field key and it's value to store changed value in parent component.
Here is the CommonStyleGenerator.js component code :
import React, { useEffect, useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
const CommonStyleGenerator = ({ style = {
height: "100%",
width: "100%",
bgColor: "#ffffff"
}, onStyleChange }) => {
useEffect(() => {
onStyleChange("height", "100%");
onStyleChange("width", "100%");
onStyleChange("bgColor", "#ffffff"); //Only this getting effect.
}, []);
return (
<View>
<TextInput
value={style?.height}
placeholder="height"
onChangeText={(text) => onStyleChange("height", text)}
style={styles.textField}
/>
<TextInput
value={style?.width}
placeholder="width"
onChangeText={(text) => onStyleChange("width", text)}
style={styles.textField}
/>
<TextInput
value={style?.bgColor}
placeholder="background color"
onChangeText={(text) => onStyleChange("bgColor", text)}
style={styles.textField}
/>
</View>
)
}
const styles = StyleSheet.create({
textField: {
borderWidth: 1,
marginVertical: 10
}
})
export default CommonStyleGenerator;
And here is the code of how I called the component in my App.js :
import React, { useEffect, useState } from 'react';
import { View, Button, Text } from 'react-native';
import CommonStyleGenerator from './components/CommonStyleGenerator';
const App = () => {
const [commonStyle, setCommonStyle] = useState(null);
return (
<View style={{flex: 1, alignItems: 'center', padding: 20}}>
<CommonStyleGenerator
style={commonStyle}
onStyleChange={(key, value) => setCommonStyle({
...commonStyle,
[key]: value
})}
/>
<Text>{JSON.stringify(commonStyle, null, 2)}</Text>
</View>
)
}
export default App;
Now, what I want is that on load CommonStyleGenerator component, generate default style if user don't change any textfield. So I called onStyleChange function on useEffect for each key. But for only last key(bgColor) function is called.
Is anyone know how I can solve this issue ?
snack.expo.io link
The commonStyle in state when the three initial onStyleChanges are called is null. Each time it's called, the new state is set with an object with a single key. The synchronous call of an onStyleChange after a previous onStyleChange hasn't updated the commonStyle variable outside yet.
Your current code is like doing:
onStyleChange({ height: '100%' });
onStyleChange({ width: '100%' });
onStyleChange({ bgColor: '#ffffff' });
so only the last object passed appears to be in state on the next render.
Use a callback instead, when setting:
onStyleChange={(key, value) => setCommonStyle(commonStyle => ({
...commonStyle,
[key]: value
}))}
In this code all I'm trying to achieve is that I get the typed value inside the value prop of Textinput. However, what I get is null. A setState is asynchronous, I'm lagging one step behind. I am new in react, and I do not know how I can make a callback function that can give me the current value.
I also wish to later use map, and make dynamic form, I appreciate solution that might work for map function as well.
thanks
import React from 'react';
import {
View,
TextInput,
} from 'react-native';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
Email: null,
Password: null,
Address: null,
};
}
EnterValue = (name) => {
return (text) => {
this.setState({
[name]: text,
});
};
};
render() {
return (
<View>
<TextInput
placeholder="enter email"
value={this.state.Email}
onChangeText={this.EnterValue('Email')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Password"
value={this.state.Password}
onChangeText={this.EnterValue('Password')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Address"
value={this.state.Address}
onChangeText={this.EnterValue('Address')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
</View>
);
}
}
I would do something like this
onChangeText={(e) => this.EnterValue(e.target.value, 'Email')}
( I'm not confident with e.target.value, if it's null or undefined, pass e.target and log it, to see what values you can get from it)
then change your function with the following
EnterValue = (value, inputName) => this.setState({ [inputName]: value});
I am pretty new to react native and am trying to get the home page of my first basic app to load. Currently, it asks users to input their "name" and "networth" and I simply want to return the networth input multiplied by a constant with an alert that appears after pressing submit saying "{name} + " net worth will be " + {newNetworth} + " next year!". However right now my output is: "undefined will be worth undefined next year!" and I cannot figure out for the life of me how to get the actual values to pass through.
Here is my child component:
import React from 'react';
import { View, Text, TouchableOpacity, TextInput, StyleSheet } from 'react-native';
class OpeningPageQs extends React.Component {
state = {
name: '',
networth: 0,
newNetworth: 0
}
nextYearWorth() {
this.setState({
name: this.state.name,
newNetworth: this.state.networth * 1.1
});
return (alert(this.name + ' will be worth ' + this.newNetworth + ' next year!'));
}
render (){
return (
<View>
<TextInput style= { styles.input }
placeholder= "name"
onChangeText= { this.name }
/>
<TextInput style= { styles.input }
placeholder= 'networth'
onChangeText= { this.networth }
/>
<TouchableOpacity style = {styles.submitButton}
onPress = {
() => this.nextYearWorth(this.state.name, this.state.networth)
}
>
<Text style={styles.submitButtonText}>
Submit
</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 23
},
input: {
margin: 15,
height: 40,
borderColor: '#7a42f4',
borderWidth: 1
},
submitButton: {
backgroundColor: '#7a42f4',
padding: 10,
margin: 15,
height: 40,
},
submitButtonText: {
color: 'white'
}
})
export default OpeningPageQs;
And here is my Parent component:
import { StatusBar } from 'expo-status-bar';
import React, { useState, Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import OpeningPageQs from './components/OpeningPageQs';
export default class App extends React.Component {
constructor (props){
super(props);
//building initial state for input props
this.state = {
name: '',
networth: this.networth
};
}
render(){
return (
<View style={styles.container}>
<StatusBar style="auto" />
<OpeningPageQs
name={this.state.name}
networth={this.state.networth}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Any help would be greatly appreciated
Reffering to: https://reactnative.dev/docs/textinput
You are wrongly setting the state. Try like this:
<TextInput style= { styles.input }
placeholder= "name"
onChangeText={text => this.setState({name: text})}
/>
It may be worth not setting the state just to show the results. You can either create local variable in nextYearWorth method, or multiple the value when setting the state inside onChangeText callback.
For the alert - please take a look at Modal component: https://reactnative.dev/docs/modal#docsNav
You can use like that.
<TextInput style= { styles.input }
placeholder= "name"
onChangeText= { text => this.name = text }
/>
I'm a newbie to React-Native, so I've been going through a tutorial to create a login screen. The code in the tutorial is out of date. I'm creating a login screen made up of a few components. However, a certain TextInput isn't showing up in the simulator. Here's the parent component "LoginForm" from LoginForm1.js:
export default class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
}
render() {
return (
<Card>
<CardSection>
<Input
placeholder="user#gmail.com"
label="Email"
value={this.state.email}
onChangeText={text => this.setState({ text })}
/>
</CardSection>
The child component "Input" is wrapped in components "CardSection" and "Card" (these pass their props with a View displaying {this.props.children}, but here's the "Input" component from Input.js:
export default class Input extends Component {
render() {
return (
<View style={styles.containerStyle}>
<Text style={styles.labelStyle}>{this.props.label}</Text>
<TextInput
placeholder={this.props.placeholder}
autoCorrect={false}
style={styles.inputStyle}
value={this.props.value}
onChangeText={this.props.onChangeText}
/>
</View>
);
}
}
const styles = StyleSheet.create({
inputStlye: {
color: '#000',
paddingRight: 5,
paddingLeft: 5,
fontSize: 18,
Height: 50,
Width: 50,
flex: 2,
},
This code doesn't throw any errors, but the TextInput from "Input" doesn't show up. I've given it some dimensions in the styling, so that can't be it. If I replace the TextInput with just normal Text, then the contents of that Text tag will appear in the simulator. Am I missing something to do with passing props? Any help would be much appreciated, thank you!
You have the value being passed down as value={this.state.email}, but you're onChangeText is updating this.state.text so just change it to value={this.state.text}.