I have tried to display a modal on click a button in react native. Initially the modal state is hidden, on click button modal should show.
But now everytime it is visible.
//Login.tsx
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TextInput, Button, TouchableOpacity, ScrollView } from 'react-native';
import axios from 'axios';
import InvalidUserModal from '../Modal/InvalidUser';
export default class LoginFirst extends Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false
};
}
triggerModal() {
this.setState(prevState => {
return {
modalVisible: true
}
});
}
render() {
return (
<View style={styles.container}>
<Button
onPress = {() => this.triggerModal()}
title = "Open Modal"
color = "orange">
</Button>
<InvalidUserModal
image = '../../../../assets/user.png'
data = 'Krunal'
display = { this.state.modalVisible }
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#0d2c4f',
justifyContent: 'center'
}
});
Modal content
import React, { Component } from 'react';
import { Modal, View, Image, Text, StyleSheet } from 'react-native';
const InvalidUser = (props) => (
<View>
<Modal
visible={props.display}
animationType={'slide'}
onRequestClose={() => console.log('closed')}
>
<View>
<Image
source={props.image}
style={styles.image}
/>
<Text style={ styles.text}>
{props.data}
</Text>
</View>
</Modal>
</View>
);
const styles = StyleSheet.create({
image: {
marginTop: 20,
marginLeft: 90,
height: 200,
width: 200
},
text: {
fontSize: 20,
marginLeft: 150
}
});
export default InvalidUser;
The above code is working fine. The only problem is modal always showing. Never hides. Please have a look on below screen.
Is there anything else to be done in the code. Realy stuck here.
I have tried to display a modal on click a button in react native. Initially the modal state is hidden, on click button modal should show.
But now everytime it is visible.
//Login.tsx
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TextInput, Button, TouchableOpacity, ScrollView } from 'react-native';
import axios from 'axios';
import InvalidUserModal from '../Modal/InvalidUser';
export default class LoginFirst extends Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false
};
}
triggerModal() {
this.setState(prevState => {
return {
modalVisible: true
}
});
}
render() {
return (
<View style={styles.container}>
<Button
onPress = {() => this.triggerModal()}
title = "Open Modal"
color = "orange">
</Button>
<InvalidUserModal
image = '../../../../assets/user.png'
data = 'Krunal'
display = { this.state.modalVisible }
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#0d2c4f',
justifyContent: 'center'
}
});
Modal content
import React, { Component } from 'react';
import { Modal, View, Image, Text, StyleSheet } from 'react-native';
const InvalidUser = (props) => (
<View>
<Modal
visible={props.display}
animationType={'slide'}
onRequestClose={() => console.log('closed')}
>
<View>
<Image
source={props.image}
style={styles.image}
/>
<Text style={ styles.text}>
{props.data}
</Text>
</View>
</Modal>
</View>
);
const styles = StyleSheet.create({
image: {
marginTop: 20,
marginLeft: 90,
height: 200,
width: 200
},
text: {
fontSize: 20,
marginLeft: 150
}
});
export default InvalidUser;
The above code is working fine. The only problem is modal always showing. Never hides. Please have a look on below screen.
Is there anything else to be done in the code. Realy stuck here.
Share Improve this question asked Jul 30, 2019 at 17:56 Jithin VargheseJithin Varghese 2,2284 gold badges31 silver badges61 bronze badges 1- You may also checkout this one when using expo and web view: github.com/Dekoruma/react-native-web-modal/tree/master/packages/… – Kurt Lagerbier Commented Oct 13, 2020 at 17:59
6 Answers
Reset to default 3I'm not sure if this will work but here is some things you should try.
Remove View
from the Modal
const InvalidUser = (props) => (
{// <View> removed }
<Modal
visible={props.display}
animationType="slide" {// you don't need {} if it's a string}
onRequestClose={() => console.log('closed')}
>
<View>
<Image
source={props.image}
style={styles.image}
/>
<Text style={ styles.text}>
{props.data}
</Text>
</View>
</Modal>
{// </View> removed }
);
setState
in a better way
If you only want to set the state to true
, you don't need to know the prevState
.
// inside triggerModal
this.setState({modalVisible: true});
Use arrow function for the class properties and avoid mutiple render of an arrow function.
// arrow function
triggerModal = () => {
this.setState({modalVisible: true});
}
render() {
return (
<View style={styles.container}>
<Button
{// avoid creating a new function on every render }
onPress = {this.triggerModal}
title = "Open Modal"
color = "orange">
</Button>
<InvalidUserModal
image = '../../../../assets/user.png'
data = 'Krunal'
display = { this.state.modalVisible }
/>
</View>
);
}
}
In my case, I was passing a state property that had not been set to false. For some reason, passing undefined
to the visible
param would make the modal appear.
I fixed it either by setting the default value on the state to false
or using visible={this.state.visible || false}
.
you should update your handler as follow if you prefer to update the state through a function rather than an object like you did. also the above two solutions is right in case you update the state as an object.
triggerModal() {
this.setState(prevState => {
return {
modalVisible: !prevState.modalVisible
}
});
}
You dont have any trigger points to close your modal which is why once you open it you arent able to close it.
in your login.tsx
toggleModal = () => this.setState({modalVisible: !this.state.modalVisible})
and pass this function to your modal as well
<InvalidUserModal
display = {this.state.modalVisible}
toggleModal = {this.toggleModal}
/>
then your modal content should be set like so:
const InvalidUser = (props) => (
<Modal
visible={props.display}
animationType="slide"
onRequestClose={props.toggleModal} //for android hardware back
>
<View>
<Image
source={props.image}
style={styles.image}
/>
<Text style={ styles.text}>
{props.data}
</Text>
<Button
title="Close"
onPress={props.toggleModal}
/>
</View>
</Modal>
);
The property that controls if the modal is visible is
this.props.display
Because the function triggerModal() controls what that value is, you have to edit that to get the modal visibility to change. In your case, it looks like there's no way for triggerModal() to return 'false'. Thus, once started, the modal would never be able to be hidden. A better solution may be:
triggerModal = () => {
this.setState({modalVisible: !this.state.modalVisible});
}
You need a way to close the model, the triggerModal method only sets the model to true it doesn't toggle the model. If you want the model to be toggle-able from the same button then you can change your method instead:
triggerModal() {
this.setState({modalVisible: !this.state.modalVisible});
}
Edit:
You also need to bind your function
<Button
onPress = {() => this.triggerModal.bind(this)}
title = "Open Modal"
color = "orange">
</Button>
If your modal still isn't hiding it isn't a matter of state, your modal could possibly be overlaying your toggle button unintentionally.