React Native/Expo: Modal not showing when 'visible' prop is true on iOS

Viewed 5300

I have an app that I've built in React Native where I have a modal that will appear when a button is pressed and prompts the user for input. I've made other modals in the app that work fine using the same method that I am using now. But when I change the state for this modal that determines whether the modal is visible, it seems to completely ignore it and does not display. The modal works on my android and on my many android emulators but it does not work on my iphone 10 for some reason.

I have a file GameScreen.js that is the screen component and holds the modal within it. It also holds the relevant methods and state for the modal's visibility:

import { 
    Body, 
    Button, 
    Container, 
    Content, 
    Header, 
    Icon, 
    Left,  
    Right,  
    View } from 'native-base';
import { BackHandler, StyleSheet, Text, TextInput, TouchableOpacity, Platform } from 'react-native';
import React, { Component, createRef } from 'react';

import myModal from '../components/myModal';

export default class GameScreen extends Component {
  constructor(props) {
    super(props)

    this.state = { 
      // other state
      isVisible: false,
    }
    this.displayModal = this.displayModal.bind(this);
  }

  displayModal(show) {
    this.setState({
      isVisible: show
    })
  }

  render() {
    return (
      <Container>
        <myModal
        displayModal={this.displayModal}
        isVisible={this.state.isVisible}
        />

        <View>
          <TouchableOpacity
          style={styles.button}
          onPress{() => this.displayModal(true)} >
            <Image />
          </TouchableOpacity>
        </View>
      </Container>
    )
  }
}

I have the modal in its own file and it looks like this (myModal.js):

import { 
    Button, 
    Card, 
    CardItem, 
    Container, 
    Text, 
    View } from 'native-base';
import { Modal, StyleSheet } from 'react-native';
import React, { Component } from 'react';

export default class myModal extends Component {

    render() {
            return (
                <Container>
                    <Modal
                    transparent 
                    animationType='fade'
                    visible={this.props.isVisible} 
                    onRequestClose={() => this.props.displayModal(false)} 
                    >
                        <View>
                           // My view stuff
                        </View>
                    </Modal>
                </Container>
            )
     }
}

I have tried putting console logs in the modal file to see if the state is actually changing and it does seem to be. I've added a log of the isVisible state in render() and in a componentDidUpdate() and it always logs out true once I have pressed the button in GameScreen but it seems like the modal is ignoring it. When I manually change the 'visible' prop to true it displays fine so it's not as if it has a problem with what I want to render.

I've also tried to run expo in production mode as some people have cited issues with dev mode and react native modals. I started the metro bundler with 'expo start --no-dev --minify' as the expo docs suggest but the problem persists.

As I said above, this exact approach is working fine in other parts of the app but seems to not like the GameScreen for some reason. And, this problem ONLY happens on iOS. I don't have any other iphones and don't have an access to a mac for xCode so I guess it might be the phone itself but it renders the other modals I have on my app just fine. I've been banging my head on the keyboard trying to get this weird bug figured out for a while, so thank you for any responses!!

1 Answers

So I just now figured it out and it was a dumb solution that I hope will help someone else. Thank you @Kamal Hossain, your suggestion helped me diagnose the problem.

So in my GameScreen, I was using an API called react-native-actions-sheet which is this nice little drawer UI component which held the button that was trying to open the modal. The button also closed the drawer after it was pressed. The button was interacting with the state just fine, but I think the process of closing the drawer was messing with the modal rendering somehow.

My working solution is to make the button wait for a fraction of a second before attempting to open the modal on ios and it works just fine now:

<TouchableOpacity
  onPress={() => {
    // closes drawer
    this.props.toggleActionSheetVisibility();
    // waits if on ios and then opens modal
    setTimeout(() => this.displayModal(true), Platform.OS === "ios" ? 200 : 0); 
  }}
/>

I don't know why it was only happening on ios specifically but I hope this helps someone in the future.

Related