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}
Related
I am trying to show or print the duration (timer) when the button start is pressed, but nothing is showing after pressing start. I tried doing Button instead of TouchableOpacity, but still, nothing changed.
class Timer extends Component {
constructor(props){
super(props)
this.state = {
count: 0
}
}
render () {
const {count} = this.state
return (
<ScrollView>
<SafeAreaView style={styles.container}>
<View style={styles.textInputContainer}>
<Text style={styles.txtHello}>Press start when ready</Text>
<View style={styles.sep}>
</View>
<TouchableOpacity style={styles.button}
onPress={ () =>
<View style={styles.textInputContainer}>
<Text>
<h2> Duration: {count}</h2>
</Text>
</View>
}
>
<Text>start</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</ScrollView>
)
}
componentDidMount(){
this.myInterval = setInterval(()=>{
this.setState({
count: this.state.count + 1
})
}, 1000)
}
}
I don't think this is a right way to do it in React. What you would like to do is set a isVisible state, change it with your onPress props in Button/TouchableOpacity and finally conditionally show the view you want to display based on that isVisible variable. Something like this:
class Timer extends Component {
constructor(props){
super(props)
this.state = {
isVisisble:false;
}
}
render(){
return(
<View>
<TouchableOpacity
onPress={ () => this.setState((prevState)=>{isVisible:!prevState.isVisible})}
>
<Text>start</Text>
</TouchableOpacity>
{this.state.isVisible && <View></View>} <- Conditional View here
</View>
)}
I have made a main screen in which I have added three button in the header, on pressing I want to open three different screens respectively but its not working.
Here's what I've tried:
constructor(props) {
super(props);
this.state = {
initialstate: 0, //Setting initial state for screens
};
}
render(){
return(
<View style={styles.container}>
<TouchableOpacity onPress={() => this.setState({ initialstate: 0})}>
<Image source={require('../../assets/add.png')}
resizeMode="contain"/>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ cardstate: 1})}>
<Image source={require('../../assets/request.png')}
resizeMode="contain"/>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ cardstate: 2})}>
<Image source={require('../../assets/send.png')}
resizeMode="contain"/>
</TouchableOpacity>
{this.state.initialstate == 0 ? ( <RequestComp/> ) : ( <TopUpComp/> ) } //Over Here when I use the Third Screen like " : <SendComp/> " it gives me JXS error says "EXPECTED }"
</View>
The first problem is that you have an initialState state variable that is only updated by the first buttons and the other two are setting cardState so even if the ternary statement was formatted correctly it wouldn't have worked either way
But aside from this problem I don't recommend using a ternary for what you're trying to do, because the conditions become difficult to read.
There are multiple ways of doing this, but I like the approach of the accepted answer here React render various components based on three logic paths). The idea is to create an object that holds a mapping of strings to components. Then you can conditionally render an item based on the current key value.
Here's an example of how you could refactor your code to use this approach:
const tabComponents = {
request: <RequestComp />,
topUp: <TopUpComp />,
send: <SendComp />,
};
class CustomTabs extends React.Component {
constructor(props) {
super(props);
this.state = {
cardstate: 'request', // Setting initial state for screens
};
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={() => this.setState({ cardstate: 'request' })}>
// Button content...
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ cardstate: 'topUp' })}>
// Button content...
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.setState({ cardstate: 'send' })}>
// Button content...
</TouchableOpacity>
{tabComponents[this.state.cardstate]}
</View>
);
}
}
Dynamically generate a TextInput when you press a button but I can’t get the value that the user digits,try to use states but I can’t because it’s not with the other general textInputs but it’s imported as Field.
try to create a state in the component file and move it to the general view and print it to see if it works and not...is there any way to bring this state?
general view:
import Campo from './campoInput';
constructor(props){
super(props);
this.state={
Cbusto:"",
Ccintura:"",
Ccadera:"",
valueArray: []
};
this.addNewEle = false;
}
agregarCampo=()=>{
this.addNewEle = true;
const newlyAddedValue = { text: 'prueba'};
this.setState({
valueArray: [...this.state.valueArray, newlyAddedValue]
});
}
render(){
return(
------Here are the normal textInput-----
<View style={{ flex: 1, padding: 4 }}>
{this.state.valueArray.map((ele) => {
return <Campo item={ele} />;
})}
</View>
<View style={styles.flex}>
<View style={styles.ButtonAdd}>
<Button
title="Add input"
color="#B13682"
onPress={this.agregarCampo}
></Button>
</View>
)
}
Component:
constructor(props){
super(props);
this.state={
info:""
};
}
render(){
return(
<View>
<Text>pruba:{this.props.item.text}</Text>
<View style={styles.input}>
<TextInput onChangeText={(text) => this.setState({info:text})}></TextInput>
</View>
</View>
)
}
can be solved by adding the onChangeText event to the Field component in the overview and in the same way in the TextInput of the component being imported, using props status
General view:
<View style={{ flex: 1, padding: 4 }}>
{this.state.valueArray.map((ele) => {
return <Campo item={ele}
onChangeText={(text) => this.setState({ info: text })}
/>;
})}
</View>
Component
<View>
<Text>pruba:{this.props.item.text}</Text>
<View style={styles.input}>
<TextInput onChangeText={this.props.onChangeText}></TextInput>
</View>
</View>
Hey there so i'm new to react native and javascript and currently i'm learning to make a custom radio button with images it looks like this my custom radio button in this page user is going to pick one button from the list, and i want to make it when the page first render it will show one pressed button and user is only allowed to pick one button. Can anyone tell me how to figure this out? Thanks in advance
here are my codes
RadioButton.js
export default class RadioButton extends Component {
constructor(props) {
super(props);
this.state = {
selected: this.props.currentSelection === this.props.value,
}
}
button() {
var imgSource = this.state.selected? this.props.normalImg : this.props.selectedImg;
return (
<Image
source={ imgSource }
/>
);
}
render() {
let activeButton = this.props.activeStyle ? this.props.activeStyle : styles.activeButton;
return (
<View style={[styles.container, this.props.containerStyle, this.state.selected || this.props.normalImg ? activeButton : inactiveButton]}>
<TouchableOpacity onPress={() => {
this.setState({ selected: !this.state.selected });
}}>
{
this.button()
}
</TouchableOpacity>
</View>
);
}
}
ActivityLog.js
class ActivityLog extends Component {
constructor(props){
super(props);
}
render() {
return (
<View style={styles.innerContainer}>
<Text style={styles.dialogText}>{`Log my activity at ${time} as...`}</Text>
<View style={styles.buttonContainer}>
<RadioButton selectedImg={img.activity.breakA} normalImg={img.activity.break} containerStyle={{marginHorizontal: normalize(10)}}/>
<RadioButton selectedImg={img.activity.meetingA} normalImg={img.activity.meeting} containerStyle={{marginHorizontal: normalize(10)}}/>
</View>
<View style={styles.buttonContainer}>
<RadioButton selectedImg={img.activity.otwA} normalImg={img.activity.otw} containerStyle={{marginHorizontal: normalize(10)}}/>
<RadioButton selectedImg={img.activity.officeA} normalImg={img.activity.office} containerStyle={{marginHorizontal: normalize(10)}}/>
</View>
);
}
}
Extract the activeStatus to ActivityLog so as to track which button is selected,right now you are maintaing a state for every button as a local state.So it is difficult to know other components to know about the button's active status.
Here is a generic implementation for rough idea.
const Child=(props)=>{
<TouchableOpacity onPress={props.handlePress}>
<Text style={[baseStyle,active && activeStyle]}>{props.title}</Text>
</TouchableOpacity>
}
class Parent extends React.Component{
state={
selectedChild:''
}
changeSelection=(sometitle)=>{
this.setState({
selectedChild:sometitle
})
}
render(){
return(
<View>
<Child handlePress={()=>this.changeSelection('1')} active={this.state.selectedChild==='1'}/>
<Child handlePress={()=>this.changeSelection('2')} active={this.state.selectedChild==='2'}/>
<Child handlePress={()=>this.changeSelection('3')} active={this.state.selectedChild==='3'}/>
<Child handlePress={()=>this.changeSelection('4')} active={this.state.selectedChild==='4'}/>
</View>
)
}
}
Expo demo Link
I've been searching around how to make a single select in Flatlist but I can't find any, here in my code I'am trying to make a single select on every cells that is inside my Flatlist.
Example: I select cell no.1, then no.1 will be selected. And if I need to select no.2, both no.1 and no.2 will be selected.
What is happening in my code is when I select no.1, it would select all cells.
export default class Dishes extends Component {
constructor(props) {
super (props)
this.state = {
data: [],
id: [],
price: [],
count: 0,
SplOrder: '',
tbl: this.props.navigation.state.params.tbl,
orderDet: this.props.navigation.state.params.orderDet,
DineIn: this.props.navigation.state.params.DineIn,
TakeOut: this.props.navigation.state.params.TakeOut,
}
}
/********************EDIT*************************
_incrementCount() {
this.setState({ count: this.state.count + 1 });
}
_decreaseCount() {
this.setState({ count: this.state.count - 1 });
}
changeTextHandler() {
this.setState({ ['count'+index]: text });
};
*/
_renderItem = ({ item, index }) => {
return (
<View>
<View>
<View>
<Text>Name: { item.menu_desc }</Text>
<View}>
<Text>Price: ₱{ item.menu_price }</Text>
<Text>Status: { item.menu_status }</Text>
</View>
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ SplOrder: text }) }
value = { this.state.SplOrder }
/>
</View>
<View>
<TouchableOpacity
onPress = {() => this._incrementCount()}>
<Text> + </Text>
</TouchableOpacity>
<TextInput
onChangeText={this.changeTextHandler}
value={this.state['count'+index].toString()} // Not working
placeholder="0"/>
<TouchableOpacity
onPress = {() => this._decreaseCount()}>
<Text> - </Text>
</TouchableOpacity>
</View>
</View>
</View>
)
}
render() {
return (
<View>
<View>
<Text>Table No: { this.state.tbl }</Text>
<Text>Order No: { this.state.orderDet }</Text>
<Text>{ this.state.DineIn }{ this.state.TakeOut }</Text>
</View>
<FlatList
data = {this.state.data}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
renderItem = {this._renderItem}
/>
<View>
<TouchableOpacity
onPress = {() => this.submit()}>
<Text>Send Order</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
The TextInputs are targeting the same state SplOrder so, if you change it in any TextInput the others will display the same. The solution I see is to put an state for each item you create.
You should do this:
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ ['SplOrder'+index]: text }) }
value = { this.state['SplOrder'+index] }
/>
The second problem we have discussed in the comments should be fixed by passing index parameter to incrementCount function.
Hi, now in the method _incrementCount() you will have to pass the index and increment each count with it index as you have in the value of. So you could do
<TouchableOpacity
onPress = {() => this._incrementCount(index)}>
<Text> + </Text>
</TouchableOpacity>
And then change your _incrementCount method adding a parameter and doing like this:
_incrementCount(index) {
this.setState({ ['count'+index]: this.state['count'+index] + 1 });
}