I'm creating an application where I'm using a MaterialBottomTabBar and in the Home Screen I've a button which are supposed to open up a <Modal>.
After investigating this for quite some time I found out that I cannot present the modal when using the tabbar. I've tried to put the modal in all my tabbar-screens (without any success). And then moved the modal over to another screen which are not included in the tab-bar and the modal worked perfectly fine.
export default function Home({ route, navigation }){
const [modal, setModal] = useState(false)
return(
<View style={styles.container}>
<Modal visible={modal} transparent={true}>
<View style={{height: "100%", width: "80%", backgroundColor: "blue"}}>
<Text>TIFMNASIFAMNFISAMFIAOFMSAOFMAFOPSAMF</Text>
</View>
</Modal>
<TouchableOpacity style={styles.addNewButton} onPress={() => setModal(true)}>
<Text style={styles.addNewButtonText}>+</Text>
</TouchableOpacity>
</View>
)
}
As you can see i'm using the React Native Hooks useState(false) and refers to it inside the Modal. But whenever I tap the <TouchableOpacity> the modal is not being presented.
NOTE!
The modal is being presented if I replace the
<Modal visible={modal} transparent={true}>
to
<Modal visible={true} transparent={true}>
But would be runned instantly, which is not an option in my case.
Do you have any idea how I can run this modal inside the screen?
Related
I have a small ReactNative app in Expo Snack that includes a single components with a TouchableOpacity.
export default function AssetExample() {
function clicked() {
alert('clicked')
}
return (
<View style={styles.container}>
<TouchableOpacity onPress={clicked()}>
<Text style={styles.paragraph}>
Click the icon
</Text>
<Image style={styles.logo} source={require('../assets/snack-icon.png')} />
</TouchableOpacity>
</View>
);
}
Every time the app is started the alert is shown, meaning TouchableOpacity triggers onPress. Why? And how can I circumvent this?
You should pass the reference of your function to TouchableOpacity like this
<TouchableOpacity onPress={clicked}>
</TouchableOpacity>
or pass it with arrow function
<TouchableOpacity onPress={()=> clicked()}>
</TouchableOpacity>
so it will be called inside TouchableOpacity component whenever required (button click), otherwise it will be called only one time during render phase.
See these docs for handling events in React https://reactjs.org/docs/handling-events.html
enter code hereI want to show a toast when my modal is visible in my react native project.
I use react-native-modal.
I have a button in modal when i press it should show up a toast
I don't want to put my toast tag inside the modal tag
what should i do???
render(){
return(
<>
<Modal visible={this.state.visible}>
<Toast
ref="toast"
style={{backgroundColor:'red'}}
position='bottom'
positionValue={100}
fadeInDuration={1000}
fadeOutDuration={1000}
opacity={0.8}
textStyle={{color:'blue'}}
/>
<SafeAreaView style={{flex:1}}>
<View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
<TouchableOpacity onPress={()=>this.refs.toast.show('hello world!')} style={{height:200,width:100,justifyContent:'center',alignItems:'center',backgroundColor:'blue'}}>
<Text>Modal Button</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</Modal>
<SafeAreaView style={{flex:1}}>
<View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
<TouchableOpacity onPress={()=>{this.setState({visible:true})}} style={{height:100,width:100,justifyContent:'center',alignItems:'center',backgroundColor:'red'}}>
<Text>button</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</>
)
}
Actually i wanna be my toast out of my Modal tag but it show in top of screen when modal is visible
react native modal is a native view, so impossible to be covered by a js component.
screen A: calling componentWillMount successfully and then navigating to screen B,
screen B: do some redux changes (that will affect the data in WillMount) and then navigating back to A but componentWillMount doesn't get called and preventing desirable data from appearing on the screen
screen A:
componentWillMount(){
this.props.fetchData();
console.log('fetched')
}
renderItem({item}){
return <Text>{item.name}</Text>
}
render(){
const array = Object.values(this.props.data)
return(
<View style={{flex: 1}}>
<Inline>
<View style={styles.container}>
<View style={styles.headerContainer}>
<Header style={styles.header} HeaderText={'EmployeeList'}
/>
</View>
<TouchableOpacity style={styles.buttonContainer}
onPress={()=> this.props.navigation.navigate('CreateEmp')}
//screen B
>
<Text style={styles.buttonStyle}>Add an Employee</Text>
</TouchableOpacity>
</View>
</Inline>
<FlatList
data={array}
renderItem={this.renderItem}
keyExtractor={array1 => array1.name}
/>
</View>
screen B:
functionOne(){
const {name, phone, createEmployee, shift} = this.props
createEmployee(name, phone, shift)
}
functionTwo(){
this.props.navigation.navigate('EmployeeList')//screen A
}
functionCombined(){
this.functionOne();
this.functionTwo();
}
and calling functionCombined in the class of course
The componentWillMount is executed when the screen is rendered.
However, when navigating to the Navigate command, if the screen is first moved, it is rendered to draw the screen, but if it is already rendered, it is not rendered again.
The function shall be moved using a push commands to run again.
functionTwo(){
this.props.navigation.push('EmployeeList')//screen A
}
I am implementing an image gallery. There's a list of squared images, if user longPress an image component it will re-render to a selected image component which show a blur background and a tick on top of the image.
Here's the normal image component:
<TouchableOpacity
key={index}
onPress={this.normalModeImgClick(img, index)}
onLongPress={this.startSelectMode(index)}
>
<Image style={styles.img} source={{uri: img.resized_xs_url}}/>
</TouchableOpacity>
Here's the component at select mode:
<TouchableOpacity
key={itemIndex}
style={styles.selectedImgWrapper}
onPress={this.selectModeImgClick(imgItem, itemIndex)}
>
<Image style={styles.img} source={{uri: imgItem.img.resized_xs_url}}/>
{imgItem.selected &&
<View style={styles.selectedImgCover}>
<Image style={styles.selectedIcon} source={require('../../assets/icon_tick.png')}/>
</View>
}
</TouchableOpacity>
As you can see, if you longPress a normal image component startSelectMode will trigger, and that image will re-render and turned to a select mode component. However, selectModeImgClick will also be triggered which it is not supposed to (as the user is still doing the longPress action).
How to prevent this happening?
Accidentally discovered an alternative right after I posted the question, solved by adding an empty onLongPress function props to the selected mode component like this:
<TouchableOpacity
key={itemIndex}
style={styles.selectedImgWrapper}
onPress={this.selectModeImgClick(imgItem, itemIndex)}
// Override 'onLongPress' with an empty function
onLongPress={() => {}}
>
<Image style={styles.img} source={{uri: imgItem.img.resized_xs_url}}/>
{imgItem.selected &&
<View style={styles.selectedImgCover}>
<Image style={styles.selectedIcon} source={require('../../assets/icon_tick.png')}/>
</View>
}
</TouchableOpacity>
Since the component is not designed to have a longPress action, I'm looking forward to better solutions:
I’m writing a React Native app and I want to detect tap/clicks anywhere on the screen so I put an onClick handler on my <View> element but it doesn’t seem to be working. Here is my render function:
<View style={styles.container} onClick={this.onClick}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
What do I need to do?
For making any element to handle touch/click events in a React-Native UI, you need to put the element inside a TouchableOpacity, TouchableWithoutFeedback, TouchableNativeFeedback or TouchableHighlight element:
<TouchableHighlight onPress = { this.onClick }>
<View style={styles.container}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
</TouchableHighlight>
Hope that helps.
In React Native version > 55.3 you make check onPress events into your View if use onStartShouldSetResponder props.
Like example:
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => console.log('You click by View')}
>
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh} />
}
>
<Text>Awesome</Text>
</ScrollView>
</View>
In example I showed how you can get onPress event on View and not blocking other event behind them. Refresh control still work correct.
In my case the following works fine. You can use onTouchStart and onTouchEnd handlers on any View via props, for example:
<View onTouchStart={() => this.doSomething()} />
More information
This worked for me...
onTouchEnd={() => alert('TAPPED')}
The easiest way to do that:
<TouchableOpacity style={styles.container} onPress={()=> whateverFunc(parameter)}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</TouchableOpacity>
So, you need to replace the 'View' component to a 'TouchableOpacity' or any other Touchable component and you also need to replace the 'onClick' prop to 'onPress'. That's all. The wrapping of a view with a TouchableWhatever component is not necessary at all.