I have a problem with onPress, tried all the solutions and did not work handleClick function,
I've tried it with following approaches as well:
onPress={this.handleClick}
onPress={this.handleClick()}
onPress={this.handleClick.bind(this)}
onPress={() => this.handleClick.bind(this)}
And I tried to change the function to:
handleClick(){
console.log('Button clicked!');
}
and this is the my code:
import React, { Component } from 'react';
import {
View,
} from 'react-native';
import Card from './common/Card';
import CardItem from './common/CardItem';
import Buttom from './common/Buttom';
import Input from './common/Input';
export default class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
}
}
onLoginPress() {
//console.log(`Email is : ${ this.state.email }`);
//console.log(`Password is : ${ this.state.password }`);
};
handleClick = () => {
console.log('Button clicked!');
};
render() {
return (
<View >
<Card>
<CardItem>
<Input
label='Email'
placeholder='Enter your email'
secureTextEntry={false}
onChangeText = { (email) => this.setState({ email })}
/>
</CardItem>
<CardItem>
<Input
label='Password'
placeholder='Enter your password'
secureTextEntry={true}
onChangeText = { (password) => this.setState({ password })}
/>
</CardItem>
<CardItem>
<Buttom onPress={this.handleClick}> Login </Buttom>
</CardItem>
</Card>
</View>
);
}
}
and this is my Buttom.js file:
import React from 'react';
import {StyleSheet, Text, TouchableOpacity} from 'react-native';
const Buttom = (props) => {
return(
<TouchableOpacity style={styles.ButtomView} >
<Text style={styles.TextButtom}> {props.children} </Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
ButtomView: {
flex: 1,
height: 35,
borderRadius: 5,
backgroundColor: '#2a3744',
justifyContent: 'center',
marginVertical: 15
},
TextButtom: {
color: '#fff',
textAlign: 'center',
fontWeight: 'bold',
fontSize: 15,
}
});
export default Buttom;
You can not bind event to Component. Event is only can attached to React Native element in React-Native or DOM in React only.
You should pass event handler,
<Buttom onPressHanlder={this.handleClick}> Login </Buttom>
In Buttom component use props.onPressHanlder to call passed event handler :
const Buttom = (props) => {
return(
<TouchableOpacity style={styles.ButtomView} onPress={props.onPressHanlder}>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<Text style={styles.TextButtom}> {props.children} </Text>
</TouchableOpacity>
);
}
bind the function to scope
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
}
this.handleClick = this.handleClick.bind(this);
}
Them <Buttom onPress={() => this.handleClick() }> Login </Buttom>
I had to restart the app after adding new packages.
(using react-native start or react-native run-android)
Related
This is what my header looks like now:
And this is what I am trying to achieve:
Code snippet:
<Stack.Navigator initialRouteName="MenuRoute">
<Stack.Screen
name={'MenuRoute'}
component={Menu}
options={({navigation, route}) => ({
headerTitle: () => (
<Text
style={{
...styles.headerTitle,
}}>
<Translatable value="Menu" />
</Text>
),
headerLeft: () => <AuthMenuPicker {...navigation} {...route} />,
headerRight: () => (
<View style={styles.row}>
<FacebookButton {...navigation} {...route}/>
<LanguagePicker />
</View>
),
headerStyle,
})}
/>
.....
.....
.....
</Stack.Navigator>
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
}
});
How can I move the Facebook Logo towards the right side (as shown in the image)?
I have tried marginLeft and paddingLeft but nothing seems to do the trick.
All help would be appreciated as I am new with this issue and with react navigation 5 in general.
UPDATE#1:
Added borderWidth:1 and borderColor: 'red' to clearly show the headerLeft area:
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
borderWidth: 1,
borderColor: 'red',
}
});
UPDATE#2 - Added component code snippets:
Code Snippet (FacebookButton component):
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Button } from 'react-native-paper';
import Entypo from 'react-native-vector-icons/Entypo';
import {FACEBOOK} from '../constants';
class FacebookButton extends Component {
constructor(props) {
super(props);
}
componentDidMount() { }
render() {
return (
<>
<Button
//onPress={() => alert()}
onPress={() => {
this.props.navigate(
'FacebookMenuWebviewRoute',
{
url: FACEBOOK.FACEBOOK_PAGE,
},
);
}}
>
<Entypo
name="facebook"
size={this.props.iconSize || 25}
style={{ ...styles.icon, ...this.props.iconStyle }}
/>
</Button>
</>
);
}
}
export const styles = StyleSheet.create({
icon: {
color: 'white',
},
});
export default FacebookButton;
Code snippet (LanguagePicker component):
import React, {Component} from 'react';
import {StyleSheet} from 'react-native';
import {Menu, Button, withTheme} from 'react-native-paper';
import Fontisto from 'react-native-vector-icons/Fontisto';
import {IntlContext} from '../utility/context/Internationalization';
class LanguagePicker extends Component {
...
...
...
renderPicker() {
return (
<IntlContext.Consumer>
{(context) => {
return (
<Menu
visible={this.state.showMenu}
onDismiss={() => this.showMenu(false)}
anchor={
<Button
onPress={() => this.showMenu(true)}
style={{
...styles.menuButton,
...this.props.menuButtonStyle,
}}>
<Fontisto
name="earth"
size={this.props.iconSize || 25}
style={{...styles.icon, ...this.props.iconStyle}}
/>
</Button>
}>
{this.renderPickerItems(context)}
</Menu>
);
}}
</IntlContext.Consumer>
);
}
render() {
return <>{this.renderPicker()}</>;
}
}
export const styles = StyleSheet.create({
menuButton: {},
icon: {
color: 'white',
},
});
export default withTheme(LanguagePicker);
Thank you #GuruparanGiritharan for pointing out about the wrappers.
Solution:
Code snippet FacebookButton component:
<TouchableOpacity
style={{ justifyContent: 'center' }}
onPress={() => { ... }
>
<Entypo
name="facebook"
size={this.props.iconSize || 25}
style={{ ...styles.icon, ...this.props.iconStyle }}
/>
</TouchableOpacity>
New Header:
Explanation:
I was using Button component from react-native-paper and the component had its own fixed spacing. This caused the Facebook icon to be too spaced out.
Thus, removing the Button component and simply adding TouchableOpacity from react-native helped to reduce the space between the two icons on the header.
I have my main app with a Text, a Text Input (a component) and a button (another component):
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Alert } from 'react-native';
import { Tinput } from './components/Tinput.js';
import { Button } from './components/Button.js';
export default function App() {
return (
<View style={styles.container}>
<Text style={{fontSize:20, padding:20, textAlign:'center'}}>Ingrese un numero del pokémon a buscar!</Text>
<Tinput/>
<Button onPress={()=> ConsultarPokemon(/*this is where i want to insert the value from Tinput */)}>
Ingresar
</Button>
<StatusBar style="auto" />
</View>
);
}
And this is my component Tinput, which has the text input:
import React from 'react';
import { TextInput } from 'react-native';
const Tinput = () => {
const [numero, setNumero] = React.useState('');
return (
<TextInput
style={{ width:'90%', height: 50, borderColor: 'gray', borderWidth: 1, backgroundColor: '#fffff0', textAlign:'center', borderRadius: 20, borderWidth:5, margin:20}}
onChangeText={(value) => setNumero({numero: value})}
value={this.state.numero}
maxLength={20}
/>
);
}
export { Tinput };
I want to use the value from the text input on my onPress function, I tried doing this but didn't work:
<Button onPress={()=> ConsultarPokemon(Tinput.state.numero)}>
Ingresar
</Button>
Also, there's an error on my Tinput component: undefined is not an object (evaluating '_this.state.numero')
So I'm probably using state the wrong way too
You will use this.state.X only if you created classes like component classes , and here is an exemple :
class Counter extends React.Component {
constructor(props) {
super(props);
this.initialCount = props.initialCount || 0;
this.state = {
count: this.initialCount
}
}
increment() {
this.setState({ count: this.state.count + 1 })
}
reset() {
this.setState({ count: this.initialCount})
}
render() {
const { count } = this.state;
return (
<>
<button onClick={this.increment.bind(this)}>+1</button>
<button onClick={this.reset.bind(this)}>Reset</button>
<p>Count: {count}</p>
</>
);
}
}
I suggest to do not complicate things and just handle onPress inside Tinput
const Tinput = () => {
const [numero, setNumero] = React.useState('');
return (
<View>
<TextInput
style={{ width:'90%', height: 50, borderColor: 'gray', borderWidth: 1, backgroundColor: '#fffff0', textAlign:'center', borderRadius: 20, borderWidth:5, margin:20}}
onChangeText={(value) => setNumero(value)}
value={numero} // no need to use this.state.numero
maxLength={20}
/>
<Button onPress={()=> ConsultarPokemon(numero)}>
Ingresar
</Button>
</View>
);
}
I am pretty new to React Native, so if the question seems stupid i am sorry in advance, i have been trying for hours to get this to work before asking this question.
I am trying to pass data from a text input to the next screen using firebase database.
I keep getting the error JSON Parse error: Unexpected identifier "undefined", I have attached below my two files, one with the text input (InputForm.js) and the other one which i want to show that data on the screen (ASTConfig1screen)
If anyone can help with this you really are a superstar!
InputForm.js
import React, { Component } from 'react';
import { StyleSheet, ScrollView, ActivityIndicator, View, TextInput } from 'react-native';
import { Button } from 'react-native-elements';
import firebase from '../Firebase';
import { withNavigation } from 'react-navigation';
class InputForm extends Component {
constructor() {
super();
this.ref = firebase.firestore().collection('boards');
this.state = {
name: '',
inventoryclass: '',
outlet: '',
isLoading: false,
};
}
updateTextInput = (text, field) => {
const state = this.state
state[field] = text;
this.setState(state);
}
saveBoard() {
this.setState({
isLoading: true,
});
this.ref.add({
name: this.state.name,
inventoryclass: this.state.inventoryclass,
outlet: this.state.outlet,
}).then((docRef) => {
this.setState({
name: '',
outlet: '',
inventoryclass: '',
isLoading: false,
});
this.props.navigation.navigate('ASTConfig1');
})
.catch((error) => {
console.error("Error adding document: ", error);
this.setState({
isLoading: false,
});
});
}
render() {
if(this.state.isLoading){
return(
<View style={styles.activity}>
<ActivityIndicator size="large" color="#ffa500"/>
</View>
)
}
return (
<ScrollView style={styles.container}>
<View style={styles.subContainer}>
<TextInput style={styles.inputtext}
placeholder={'Name'}
placeholderTextColor="white"
value={this.state.name}
onChangeText={(text) => this.updateTextInput(text, 'name')}
/>
</View>
<View style={styles.subContainer}>
<TextInput style={styles.inputtext}
multiline={true}
numberOfLines={4}
placeholder={'Inventory Class'}
placeholderTextColor="white"
value={this.state.inventoryclass}
onChangeText={(text) => this.updateTextInput(text, 'inventoryclass')}
/>
</View>
<View style={styles.subContainer}>
<TextInput style={styles.inputtext}
placeholder={'Outlet'}
placeholderTextColor="white"
value={this.state.outlet}
onChangeText={(text) => this.updateTextInput(text, 'outlet')}
/>
</View>
<View style={styles.button}>
<Button
large
leftIcon={{name: 'save'}}
title='Save'
onPress={() => this.saveBoard()} />
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20
},
subContainer: {
flex: 1,
marginBottom: 20,
padding: 5,
borderBottomWidth: 2,
borderBottomColor: '#CCCCCC',
},
inputtext: {
color: 'white',
fontSize: 20
},
activity: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
}
})
export default withNavigation(InputForm);
and this is where i would like to show the data on this screen
ASTConfig1.js
import React from 'react';
import {
View,
Text,
StyleSheet,
Button,
ImageBackground,
StatusBar,
SafeAreaView,
TextInput,
ScrollView,
UIManager,
ActivityIndicator
}
from 'react-native';
import {AccordionList} from "accordion-collapse-react-native";
import { Separator } from 'native-base';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
import firebase from '../Firebase';
import Logo from '.././components/Logo';
import Colors from '.././constants/Colors';
import Search from '.././components/Search';
import InputForm from '.././components/InputForm';
class ASTConfig1Screen extends React.Component {
static navigationOptions = {
title: 'ASTConfig1',
};
constructor(props) {
super(props);
this.state= {
isLoading: true,
board: {},
key: '',
status:true,
text: '',
list:[
{
title: 'Getting Started',
body: 'React native Accordion/Collapse component, very good to use in toggles & show/hide content'
},
{
title: 'Components',
body: 'AccordionList,Collapse,CollapseHeader & CollapseBody'
},
{
title: 'Test',
body: 'AccordionList,Collapse,CollapseHeader & CollapseBody'
}
],
}
}
componentDidMount() {
const { navigation } = this.props;
const ref = firebase.firestore().collection('boards').doc(JSON.parse(navigation.getParam('boardkey')));
ref.get().then((doc) => {
if (doc.exists) {
this.setState({
board: doc.data(),
key: doc.id,
isLoading: false
});
} else {
console.log("No such document!");
}
});
}
_head(item){
return(
<Separator bordered style={{alignItems:'center'}}>
<Text>{item.title}</Text>
</Separator>
);
}
_body(item){
return (
<View style={{padding:10}}>
<Text style={{textAlign:'center'}}>{item.body}</Text>
</View>
);
}
ShowHideTextComponentView = () =>{
if(this.state.status == true)
{
this.setState({status: false})
}
else
{
this.setState({status: true})
}
}
render() {
if(this.state.isLoading){
return(
<View style={styles.activity}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
)
}
return (
<View style={styles.screen}>
<ImageBackground
source={require('.././assets/Img/BackGround2.png')}
style={styles.background}>
</ImageBackground>
<SafeAreaView>
<View style={{flex: 1, justifyContent: 'space-between', width: wp('80%')}}>
<View style={styles.logotop}>
<Logo/>
</View>
<View style={styles.editstock}>
<Text style={styles.editstocktext}>EDIT STOCK LIST:</Text>
</View>
{/*Start of 3 buttons Firebase*/}
<View style={styles.three}>
<View style={styles.edit1}>
<Text style={styles.textheader}>{this.state.board.name}</Text>
<Button style={styles.edit} title='Edit' ></Button>
</View>
<View style={{padding: 3}}></View>
<View style={styles.edit2}>
<Text style={styles.text}>{this.state.board.inventoryclass}</Text>
<Button style={styles.edit} title='Edit' ></Button>
</View>
<View style={styles.edit3}>
<Text style={styles.text}>{this.state.board.outlet}</Text>
<Button style={styles.edit} title='Edit' ></Button>
</View>
</View>
{/*End of 3 buttons Firebase*/}
{/*Start of AccordionList*/}
<ScrollView>
<View style={styles.middle}>
<AccordionList
list={this.state.list}
header={this._head}
body={this._body}
/>
</View>
</ScrollView>
{/*End of AccordionList*/}
{/*Start of Search*/}
<View>
{
this.state.status ? null : <View style={styles.bottom}>
<Text style={styles.textbottom}>SEARCH FOR NEW ITEMS:</Text>
<Search />
</View>
}
<Button title="ADD" onPress={this.ShowHideTextComponentView} />
</View>
</View>
</SafeAreaView>
</View>
);
};
};
{/*End of Search*/}
export default ASTConfig1Screen;
but it returns the error - Error adding document: [SyntaxError: SyntaxError: SyntaxError: JSON Parse error: Unexpected identifier "undefined"
in inputform.js saveBoard function you should
this.props.navigation.navigate('Details', {
'ASTConfig1': docRef
});
and remove JSON.parse form other file
I have a Reminder Component with a simple form comprising of one TextInput from react-native and one DatePicker from native-base and one submit to store the value on click.
I am trying to implement AyncStorage to store those values locally and later display them on another screen. But I am unable to do so, as I am getting an error 'Value is not defined.'
Whatever blog posts and tuts, the person was storing only one single property. I want to store complete state i.e input field and the date onclick of the save button.
This is my ReminderComponent
import React, { Component } from 'react';
import { View,StyleSheet, AsyncStorage, TextInput } from 'react-native';
import {
Form,
Button, Icon,
DatePicker, Text
} from 'native-base';
import PropTypes from 'prop-types';
class Reminder extends Component {
constructor(props) {
super(props);
this.state = {
input: '',
chosenDate: new Date(),
};
this.setDate = this.setDate.bind(this);
this.handleChangeInput = this.handleChangeInput.bind(this);
this.saveData = this.saveData.bind(this);
}
setDate(newDate) {
this.setState({
chosenDate: newDate
});
}
handleChangeInput = (text) => {
this.setState({input:text});
}
//On application loads, this will get the already saved data and set
//the state true when it's true.
componentDidMount() {
AsyncStorage.getItem("key").then((value) => {
this.setState({'key':value});
});
}
//save the input
saveData(value) {
console.log('value', value);
AsyncStorage.setItem("key", value);
this.setState({'key':value});
}
render() {
const {input} = this.state;
return (
<View>
<Form style={styles.formContainer}>
<View style={styles.formView}>
< TextInput
placeholder = "Set your reminder"
onChangeText={this.handleChangeInput}
value={this.state.input}
/>
<DatePicker
defaultDate={new Date()}
minimumDate={new Date(2018, 1, 1)}
maximumDate={new Date(2019, 12, 31)}
locale={"en"}
timeZoneOffsetInMinutes={undefined}
modalTransparent={false}
animationType={"fade"}
androidMode={"default"}
placeHolderText="Select date"
textStyle={{ color: "green" }}
placeHolderTextStyle={{ color: "#d3d3d3" }}
onDateChange={this.setDate}
/>
<Text style={styles.datePicker}>
{this.state.chosenDate.toString().substr(4, 12)}
</Text>
</View>
<View style={styles.footer}>
<Button block success style={styles.saveBtn}
onPress={ () =>
{this.saveData()
console.log('save data', value);}
}
>
<Icon type='MaterialIcons' name='done' />
</Button>
</View>
</Form>
</View>
);
}
}
const styles = StyleSheet.create({
formContainer: {
marginTop: 10,
padding: 10,
},
editIcon:{
color: '#28F1A6',
fontSize: 26,
},
editBtn:{
flex: 1,
alignSelf: 'flex-end',
},
datePicker:{
alignSelf: 'auto',
paddingLeft: 10
},
footer:{
position: 'relative',
top: 350
},
saveBtn: {
position:'relative',
marginTop: 35,
}
});
export default Reminder;
This is my ReminderScreen.
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import PropTypes from 'prop-types';
import Reminder from '../components/Reminder';
const ReminderScreen = ({navigation}) => (
<View >
<Reminder navigation={navigation} >
<StatusBar backgroundColor = "#28F1A6" />
</Reminder >
</View>
);
Reminder.propTypes = {
navigation: PropTypes.object.isRequired
}
export default ReminderScreen;
Some tweaks needed in the saveData function and get items from Asyncstorage.
While storing the data in AsyncStorage just convert entire state as a string and save it. For retrieving just convert the string to JSON object and set the value in setState function.
Please see the modified code below for Remainder component.
import React, { Component } from 'react';
import { View,StyleSheet, AsyncStorage, TextInput } from 'react-native';
import {
Form,
Button, Icon,
DatePicker, Text
} from 'native-base';
import PropTypes from 'prop-types';
class Reminder extends Component {
constructor(props) {
super(props);
this.state = {
input: '',
chosenDate: new Date(),
};
this.setDate = this.setDate.bind(this);
this.handleChangeInput = this.handleChangeInput.bind(this);
this.saveData = this.saveData.bind(this);
}
setDate(newDate) {
this.setState({
chosenDate: newDate
});
}
handleChangeInput = (text) => {
this.setState({input:text});
}
//On application loads, this will get the already saved data and set
//the state true when it's true.
componentDidMount() {
AsyncStorage.getItem("key").then((value) => {
this.setState(JSON.parse(value));
});
}
//save the input
saveData() {
AsyncStorage.setItem("key", JSON.stringify(this.state));
}
render() {
const {input} = this.state;
return (
<View>
<Form style={styles.formContainer}>
<View style={styles.formView}>
< TextInput
placeholder = "Set your reminder"
onChangeText={this.handleChangeInput}
value={this.state.input}
/>
<DatePicker
defaultDate={new Date()}
minimumDate={new Date(2018, 1, 1)}
maximumDate={new Date(2019, 12, 31)}
locale={"en"}
timeZoneOffsetInMinutes={undefined}
modalTransparent={false}
animationType={"fade"}
androidMode={"default"}
placeHolderText="Select date"
textStyle={{ color: "green" }}
placeHolderTextStyle={{ color: "#d3d3d3" }}
onDateChange={this.setDate}
/>
<Text style={styles.datePicker}>
{this.state.chosenDate.toString().substr(4, 12)}
</Text>
</View>
<View style={styles.footer}>
<Button block success style={styles.saveBtn}
onPress={ () =>
{this.saveData()
console.log('save data', value);}
}
>
<Icon type='MaterialIcons' name='done' />
</Button>
</View>
</Form>
</View>
);
}
}
const styles = StyleSheet.create({
formContainer: {
marginTop: 10,
padding: 10,
},
editIcon:{
color: '#28F1A6',
fontSize: 26,
},
editBtn:{
flex: 1,
alignSelf: 'flex-end',
},
datePicker:{
alignSelf: 'auto',
paddingLeft: 10
},
footer:{
position: 'relative',
top: 350
},
saveBtn: {
position:'relative',
marginTop: 35,
}
});
export default Reminder;
I want to get the value of the email and passowrd in my Form.js, so that click click button can pass them a client api
1. this is my class src/components/login/Form.js
import React, { Component } from 'react';
import {
KeyboardAvoidingView,
StyleSheet,
TouchableHighlight,
Image,
} from 'react-native';
import UserInput from "./UserInput";
import usernameImg from '../../images/Iconperson.png';
import passwordImg from '../../images/Iconlock.png';
import eyeImg from '../../images/eye.png';
export default class Form extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
};
}
_onPress() {
console.warn("email", this.state.email)
console.warn("password", this.state.password)
}
render() {
return (
<KeyboardAvoidingView behavior='padding'
style={styles.container}>
<UserInput source={usernameImg}
onChangeText = {(email) => this.setState({email})}
keyboardType = 'email-address'
placeholder='Username'
autoCapitalize={'none'}
returnKeyType={'done'}
autoCorrect={false} />
<UserInput source={passwordImg}
onChangeText = {(password) => this.setState({password})}
placeholder='Password'
returnKeyType={'done'}
autoCapitalize={'none'}
autoCorrect={false} />
<TouchableHighlight
onPress={this._onPress}
activeOpacity={1} >
<Text>LOGIN</Text>
</TouchableHighlight>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
}
});
2. this is my class src/components/login/UserInput.js
import React, { Component , PropTypes} from 'react';
import Dimensions from 'Dimensions';
import {
StyleSheet,
View,
TextInput,
Image,
} from 'react-native';
const DEVICE_WIDTH = Dimensions.get('window').width;
const DEVICE_HEIGHT = Dimensions.get('window').height;
export default class UserInput extends Component {
render() {
return (
<View style={styles.inputWrapper}>
<Image source={this.props.source}
style={styles.inlineImg} />
<TextInput style={styles.input}
onChangeText = {(this.props.ChangeText) =>
this.setState({field})}
placeholder={this.props.placeholder}
secureTextEntry={this.props.secureTextEntry}
autoCorrect={this.props.autoCorrect}
autoCapitalize={this.props.autoCapitalize}
returnKeyType={this.props.returnKeyType}
placeholderTextColor='white'
keyboardType ={this.props.keyboardType}
underlineColorAndroid='transparent' />
</View>
);
}
}
UserInput.propTypes = {
ChangeText : PropTypes.string,
source: PropTypes.number.isRequired,
placeholder: PropTypes.string.isRequired,
keyboardType : PropTypes.string,
secureTextEntry: PropTypes.bool,
autoCorrect: PropTypes.bool,
autoCapitalize: PropTypes.string,
returnKeyType: PropTypes.string,
};
const styles = StyleSheet.create({
input: {
backgroundColor: 'rgba(255, 255, 255, 0.2)',
width: DEVICE_WIDTH - 40,
height: 40,
marginHorizontal: 20,
paddingLeft: 45,
borderRadius: 20,
color: '#ffffff',
},
inputWrapper: {
flex: 1,
},
inlineImg: {
position: 'absolute',
zIndex: 99,
width: 22,
height: 22,
left: 35,
top: 9,
},
});
As you are typing into the TextInput I see you are trying to change the state in the Form component. For this to happen correctly, setState needs to be called from the Form component. There are a couple functions currently being passed down through props:
(email) => this.setState({email})
// and
(password) => this.setState({password})
Looking at how those are being used in your UserInput component, whenever a new character is added to that text box, invoke the function above. so when this.setState() is called, it is saying UserInput.setState(). Since we want to change the state in Form we have to bind those functions to the parent component.
Instead of passing the functions directly to props, let's add some user methods:
export default class Form extends Component {
constructor(props) {}
_onChangeEmail(email) {
this.setState(Object.assign({}, state, { email })); // good practice for immutability
}
_onChangePassword(password) {
this.setState(Object.assign({}, state, { password })); // good practice for immutability
}
render() {}
}
Next, we need to bind these class methods to itself. That way no matter where these are called, this will always point to the Form component. This is most commonly done in the constructor:
export default class Form extends Component {
constructor(props) {
super(props)
this.state = {}
// this is where we do the binding
this._onChangeEmail = this._onChangeEmail.bind(this)
this._onChangePassword = this._onChangePassword.bind(this)
}
_onChangeEmail(email) { /* code */}
_onChangePassword(password) { /* code */}
render() {}
}
Now pass these down to the UserInput component through props:
// Form.js
render() {
return (
<KeyboardAvoidingView>
<UserInput onChangeText={this._onChangeEmail} />
<UserInput onChangeText={this._onChangePassword} />
</KeyboardAvoidingView>
)
}
These methods should now be used when the user inputs text:
export default class UserInput extends Component {
render() {
return (
<View>
<Image />
<TextInput onChangeText = {this.props.onChangeText} />
</View>
);
}
}
Bonus: You also should add a property 'value' to the text input:
export default class UserInput extends Component {
render() {
return (
<View>
<Image />
<TextInput
onChangeText={this.props.onChangeText} />
value={this.props.textValue}
</View>
);
}
}
And make sure it is passed down from the parent component:
// Form.js
render() {
return (
<KeyboardAvoidingView>
<UserInput
onChangeText={this._onChangeEmail}
textValue={this.state.email}/>
<UserInput
onChangeText={this._onChangePassword}
textValue={this.state.password}/>
</KeyboardAvoidingView>
)
}
The value of TextInput may be retrieved through its _lastNativeTextproperty.
this.refs.myTextInput._lastNativeText
See this answer