React-Native Controlled Modal Freezing

Viewed 7097

Disclaimers: Only can test on iPhone emulator atm. React-Native 0.49 Mac OSX High Sierra

I want to create a modal which gets its props from a parent component. As below:

const Modal = ({ showModal, closeModal }) => (
  <Modal
    animationType="slide"
    transparent={false}
    visible={showModal}
    onRequestClose={() => {alert("Modal has been closed.")}}
    >
   <View style={{marginTop: 22}}>
     <Text>Hello World!</Text>
     <TouchableHighlight onPress={() => closeModal() }>
        <Text>Hide Modal</Text>
     </TouchableHighlight>
   </View>
  </Modal>
);

This is the parent example:

<View>
  <Modal
    showModal={this.state.showModal}
    closeModal={() => this.setState({ showModal: false })}
  />
  <ScrollView>
      {elements.map(element => {
        return (
          <Card key={element.id}>  
            <Badge onPress={() => this.setState({ showModal: true })>
              <Text>Show</Text>
            </Badge>
          </Card>
        );
      })}
  </ScrollView>
</View>

When I click the show modal button the modal pops-up as expected but when I click closeModal then the modal disappears and reappears again but this time I cannot interact with it, the UI seems as if it is frozen, I have to then restart the emulator.

If I copy and paste the code straight from the React-Native docs: https://facebook.github.io/react-native/docs/modal.html The modal works fine. It is a self-contained component though.

Any help/advice would be much appreciated.

Regards, Emir

6 Answers

After painfully rebuilding the component from scratch I see there was a unsuspected culprit:

componentWillUpdate() {
    UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
    LayoutAnimation.easeInEaseOut();
  }

When I removed this code the modal worked fine but when I added it back it froze when I tried to close. This seems to be some animation conflict in iOS cant confirm for Android.

When I added a timeout of 1000ms the screen revealed a little more before it froze again.

So for now if someone has the same issue look for multiple animations being called.

Hope this helps someone, and if you have a better way of solving it please do let me know.

Regards, Emir

Very late, but issue still exist in latest version, And only solution i found is make different views in render method.

one for modal and one for other component.

render() {
    if (showErrorModal) {
      return (
          <ModalError message={message} visible={showErrorModal} handleBack={this.handleBack} />
      );
    }

    return (
        <ScrollView style={{ flex: 1 }}>
          <View style={{ padding: 10, paddingVertical: 20 }}>
            {!active ? this.fieldlabel() : this.fieldSelect()}
          </View>

        // remove this one, do not use here. it will block the UI
        {* <ModalError message={message} visible={showErrorModal} handleBack={this.handleBack} /> *}
        </ScrollView>
    );
  }
}

Make sure that your <Modal/> is wrapped in a <View/>.

Inside your Parent component, create a function will set showModal to false.

Parent

closeModal = () => {
  this.setState({
    showModal: false
  });
}

Then you need to pass it down to your Modal, via props.

<Modal showModal={this.state.showModal} closeModal={this.closeModal} />

Inside of your Modal, change: <TouchableHighlight onPress={() => this.closeModal() }>

To: <TouchableHighlight onPress={closeModal}>

Why do u use this.closeModal()? Use the one u are getting from the props,i.e just closeModal().

<TouchableHighlight onPress={() => closeModal() }>
Related