Jithin Varghese
Jithin Varghese

Reputation: 2228

react native modal always visible

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.

App screen

Is there anything else to be done in the code. Realy stuck here.

Upvotes: 6

Views: 11627

Answers (6)

Karan Wadhwa
Karan Wadhwa

Reputation: 86

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>
);

Upvotes: 2

Henrique Mazer
Henrique Mazer

Reputation: 409

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}.

Upvotes: 3

Vencovsky
Vencovsky

Reputation: 31565

I'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>
      );
    }
}

Upvotes: 3

samo0ha
samo0ha

Reputation: 3788

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
      }
    });
 }

Upvotes: 2

Perniferous
Perniferous

Reputation: 611

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.

Upvotes: 1

matthewjgunton
matthewjgunton

Reputation: 21

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});
}

Upvotes: 1

Related Questions