Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS: UI will be blocked when show Alert while closing Modal #10471

Closed
nihgwu opened this issue Oct 20, 2016 · 176 comments
Closed

iOS: UI will be blocked when show Alert while closing Modal #10471

nihgwu opened this issue Oct 20, 2016 · 176 comments

Comments

@nihgwu
Copy link
Contributor

@nihgwu nihgwu commented Oct 20, 2016

When show Alert while closing Modal, the Alert dialog will disappear and the Modal will block the UI entirely even after reload, only on iOS.

'use strict';

import React, { Component } from 'react';

import {
  StyleSheet,
  View,
  Text,
  Modal,
  Alert,
} from 'react-native';

class demo extends Component {
  state = {
    showModal: false,
  }

  onShowModal = () => {
    this.setState({ showModal: true });
  }
  onCloseModal1 = () => {
    this.setState({ showModal: false }, () => {
      Alert.alert('Alert', 'UI will be blocked by the modal');
    });
  }
  onCloseModal2 = () => {
    this.setState({ showModal: false }, () => {
      setTimeout(() => {
        Alert.alert('Alert', 'Alert won\'t show');
      }, 200);
    });
  }
  onCloseModal3 = () => {
    this.setState({ showModal: false }, () => {
      setTimeout(() => {
        Alert.alert('Alert', 'Works fine');
      }, 510);
    });
  }
  render() {
    const { showModal } = this.state;
    return (
      <View style={styles.container}>
        <Text onPress={this.onShowModal}>Show modal</Text>
        <Modal animationType='slide' visible={showModal} onRequestClose={this.onCloseModal3} >
          <View style={styles.container}>
            <Text onPress={this.onCloseModal1}>Close modal immediately</Text>
            <Text onPress={this.onCloseModal2}>Close modal after 200ms</Text>
            <Text onPress={this.onCloseModal3}>Close modal after more then 500ms</Text>
          </View>
        </Modal>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'space-around',
  },
});


export default demo;
@nihgwu nihgwu changed the title UI is blocked when show Alert while closing Modal UI will be blocked when show Alert while closing Modal Oct 20, 2016
@leeight

This comment has been minimized.

Copy link
Contributor

@leeight leeight commented Oct 20, 2016

+1

@alma-socar

This comment has been minimized.

Copy link

@alma-socar alma-socar commented Oct 20, 2016

InteractionManager.runAfterInteractions also doesn't work in this case.

This is really frustrating.

@ganmor

This comment has been minimized.

Copy link

@ganmor ganmor commented Oct 20, 2016

The opposite is also true, showing an alert in the same loop just before showing a modal will prevent the modal from being displayed

@nihgwu

This comment has been minimized.

Copy link
Contributor Author

@nihgwu nihgwu commented Oct 20, 2016

Yes, I guess they are the some issue, so I just make it simple to demonstrate

? 2016?10?20??20:07?Morgan Laupies <notifications@github.commailto:notifications@github.com> ???

The opposite is also true, showing an alert in the same loop just before showing a modal will prevent the modal from being displayed

You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHubhttps://github.com//issues/10471#issuecomment-255087481, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ACeY8qW8mq4UpMUPScI2sI6Uhu6dFTOlks5q11mNgaJpZM4Kbxlp.

@K-Leon

This comment has been minimized.

Copy link
Contributor

@K-Leon K-Leon commented Oct 21, 2016

I noticed same issue with experimental navigator. An Error while transitioning kills the animation and freezes UI.

@ericvicenti ericvicenti changed the title UI will be blocked when show Alert while closing Modal iOS: <Modal> should inform InteractionManager while animating Oct 24, 2016
@ericvicenti

This comment has been minimized.

Copy link
Contributor

@ericvicenti ericvicenti commented Oct 24, 2016

Looks like we need <Modal> animations to tie into InteractionManager. A PR would be appreciated for this!

Any issues with NavigationExperimental should be filed separately.

@nihgwu

This comment has been minimized.

Copy link
Contributor Author

@nihgwu nihgwu commented Oct 25, 2016

@ericvicenti I didn't use NE or Navigator in demo at all, and I don't think this issue is related to InteractionManager, my guess is that Modal and Alert are using the same controller or view, so there will be a conflict when trying to control them simultaneously, I know nothing about iOS or I would be glad to make a PR, because it's really annoying but has a quite common use case

In my demo, I've show the different results when waiting for a certain milliseconds. I guess the Modal need 500ms to dismiss, so it's safe to show the Alert after 500ms. Perhaps you are right to tie Modal animations into InteractionManager, but what if I show the Alert first as @ganmor mentioned above, I can't close the Alert manually, or if I could, would there be the same occasion that we need to wait for the InteractionManager before showing the Modal?

Would someone expert in iOS take a look at this issue?

@nihgwu nihgwu changed the title iOS: <Modal> should inform InteractionManager while animating iOS: UI will be blocked when show Alert while closing Modal Nov 4, 2016
@nihgwu

This comment has been minimized.

Copy link
Contributor Author

@nihgwu nihgwu commented Nov 4, 2016

ping @grabbou

facebook-github-bot pushed a commit that referenced this issue Nov 5, 2016
Summary:
further discussion: should there be a `onClose` or `onClosed` to pair with `onShow`? which would make a workaround for #10471 much easier
Closes #10669

Differential Revision: D4133832

Pulled By: hramos

fbshipit-source-id: 644a5bb6b9da697c81fc96ae4da196ba5b4050cb
@DevBkIL

This comment has been minimized.

Copy link

@DevBkIL DevBkIL commented Nov 7, 2016

do someone have a fix for it?

@jasonmerino

This comment has been minimized.

Copy link

@jasonmerino jasonmerino commented Nov 7, 2016

@DevBkIL my not great solution is to set a timeout, enough for the presented view controller to be the one under the Modal, and then present the Alert. Like I said, not great, but it's working until this can be properly resolved.

mlguys added a commit to mlguys/react-native that referenced this issue Nov 8, 2016
Summary:
further discussion: should there be a `onClose` or `onClosed` to pair with `onShow`? which would make a workaround for facebook#10471 much easier
Closes facebook#10669

Differential Revision: D4133832

Pulled By: hramos

fbshipit-source-id: 644a5bb6b9da697c81fc96ae4da196ba5b4050cb
@nihgwu

This comment has been minimized.

Copy link
Contributor Author

@nihgwu nihgwu commented Nov 12, 2016

UPDATE: UI will be blocked when show Share/ActionSheet while closing Modal too
And if we are showing the Alert/Share/ActionSheet, then show a Modal, the UI will be froze too
ping @javache @mkonicek

@joegoodall1

This comment has been minimized.

Copy link

@joegoodall1 joegoodall1 commented Nov 21, 2016

Any update/resolution to this? We're still having problems with this a month after this issue was first reported.

@mjamiesoncs

This comment has been minimized.

Copy link

@mjamiesoncs mjamiesoncs commented Nov 21, 2016

+1

@sibelius

This comment has been minimized.

Copy link

@sibelius sibelius commented Nov 21, 2016

I can confirm this using https://github.com/jaysoo/react-native-prompt

any workaround?

@baurine

This comment has been minimized.

Copy link

@baurine baurine commented Nov 23, 2016

today I met the similar problem after I upgraded the react-native from 0.33 to 0.37. I want to show an Alert dialog after close the Modal, but Modal doesn't disappear, even after I close the Alert dialog and use cmd + R to reload the app. only in iOS, and it works fine by react-native 0.33.

the code likes following:

  renderModal() {
    return (
      <Modal
        animationType = 'fade'
        transparent={true}
        visible={this.state.isProcessing}
        onRequestClose={()=>{}}>
        <View style={styles.modalContainer}>
          <LoadingSpiner size='large' color='white' styleAttr='Normal'/>
        </View>
      </Modal>
    )
  }

  _pressNext() {
    // display a Modal with a spinner
    this.setState({isProcessing: true}}

    // network request
    // ...
  }

  componentWillReceiveProps(nextProps) {
      // ...

      // to hide the Modal with a spinner
      this.setState({isProcessing: false})
      Alert.alert('title', 'Something has done!', [
        { text: 'Got it', onPress: () => {} }
      ])
    }
  }

then I try to use setTimeout to work around it, the code likes following:

  componentWillReceiveProps(nextProps) {
      // ...

      // to hide the Modal with a spinner
      this.setState({isProcessing: false})
      setTimeout( () => {
        // this log will output
        console.log("show alert")
        // but Alert doesn't display
        // sometimes it will display occasionally
        Alert.alert("title", "msg")   
      }, 200)
  }

then the Modal will disappear, but, the Alert dialog can't display!!!

I also tried run setTimeout in setState callback, like this:

  this.setState({isProcessing: false}, () => {
    setTimeout( () => {
      Alert.alert("title", "msg")
    }, 200)
  }

but the same result, Alert dialog doesn't pop up yet.

finally, I decide to hide Modal after I close the Alert dialog, and that works! code likes following:

Alert.alert("title", "msg", [
  { text: "OK", onPress: () => { this.setState({ isProcessing: false } }    
])
@vicmpen

This comment has been minimized.

Copy link

@vicmpen vicmpen commented Nov 23, 2016

@baurine
Had the same problem with RN 35, a little higher timeout worked for me (600), but ultimately i also did what you did, hide the modal on OK Pressed in Alert

return Alert.alert('Σφάλμα','Η υπηρεσία δεν είναι διαθέσιμη αυτή τη στιγμή. Παρακαλούμε δοκιμάστε σε λίγο.', [ {text: 'OK', onPress: () =>this.setState ({spinnerIsVisible:false})} ])

@b8ne

This comment has been minimized.

Copy link

@b8ne b8ne commented Nov 29, 2016

We are having a similar issue in niftylettuce/react-native-loading-spinner-overlay. Could it be that this is a more general issue relating to UI updating on state change rather than just a modal issue?

@ericvicenti

This comment has been minimized.

Copy link
Contributor

@ericvicenti ericvicenti commented Nov 29, 2016

@AlimovSV

This comment has been minimized.

Copy link

@AlimovSV AlimovSV commented Dec 1, 2016

+1

1 similar comment
@mattotodd

This comment has been minimized.

Copy link

@mattotodd mattotodd commented Dec 1, 2016

+1

@susan-github

This comment has been minimized.

Copy link

@susan-github susan-github commented Dec 4, 2016

+1, anyone has found solutions?

@rogerbright

This comment has been minimized.

Copy link

@rogerbright rogerbright commented May 29, 2019

The timeout workaround seems to work but it's clunky at best. There's no guarantee that 500ms (or any arbitrary time) will always be enough. Are the developers too busy making self-indulgent breaking changes to all the other RN APIs to fix basic issues? (Sorry, I'm frustrated.)

@cltsang

This comment has been minimized.

Copy link

@cltsang cltsang commented May 30, 2019

If we are using navigation libraries from third parties anyway, we should use modal from third party library too, as one could argue that it belongs to navigation.

If you use react-navigation, just use StackNavigator with transparentCard set to true, and mode set to 'modal'.
See: https://reactnavigation.org/docs/en/stack-navigator.html#stacknavigatorconfig

In my opinion, navigation is such a fundamental interaction that it should be included in the core. But it is what it is.

@zhongwuzw

This comment has been minimized.

Copy link
Collaborator

@zhongwuzw zhongwuzw commented Jun 6, 2019

Hi all, I'll be closing this because we may fixes it in master branch, feel free to reopen if you think bug not fixed.

@zhongwuzw zhongwuzw closed this Jun 6, 2019
@IlarionHalushka

This comment has been minimized.

Copy link

@IlarionHalushka IlarionHalushka commented Jun 9, 2019

still have it in rn 0.59.8

@zhongwuzw

This comment has been minimized.

Copy link
Collaborator

@zhongwuzw zhongwuzw commented Jun 9, 2019

still have it in rn 0.59.8

@IlarionHalushka Hey, we still don't release yet, please test on master branch.

@IlarionHalushka

This comment has been minimized.

Copy link

@IlarionHalushka IlarionHalushka commented Jun 10, 2019

oh, sorry for my misunderstanding... Unfortunately I wasn't able to test on master branch because ios build failed for me:(
For now I fixed the issue with work-around by hiding modal on Alert OK press. Anyway thanks a lot!

@maxKimoby

This comment has been minimized.

Copy link

@maxKimoby maxKimoby commented Jul 11, 2019

2 years later and it is still a thing. Can't hide 2 modals in a single setState call because of this. You got to manually set a timeout for the second one to close.

ElyDev added a commit to ElyDev/YungDevz that referenced this issue Jul 16, 2019
Alert.alert cancels Modal dismiss even so we end up with a non responsive Modal confirmation dialog. This is explained here:
facebook/react-native#10471

I used the workaround suggested in the thread by adding a short timeout to Alert.alert

Todo: eventually we should better handle this by launching the error dialog from the teacher screen instead of redux, but this workaround is good for now.
@deepas96

This comment has been minimized.

Copy link

@deepas96 deepas96 commented Jul 16, 2019

Still having this issue. I am showing a loader on screen which is a Modal and then I need to show popup after API response. It works on Android to hide loader on Ok button action of Alert popup, but not working on iOS. Loader gets stuck on screen and popup never appears.
Getting this error on Xcode :
Warning: Attempt to present <RCTModalHostViewController: 0x7fda01a0d970> on <UIViewController: 0x7fd9fe447fd0> which is already presenting <RCTModalHostViewController: 0x7fda01a0d2d0>
Need to kill the app and restart it. Can anyone have solution?

@deepas96

This comment has been minimized.

Copy link

@deepas96 deepas96 commented Jul 16, 2019

oh, sorry for my misunderstanding... Unfortunately I wasn't able to test on master branch because ios build failed for me:(
For now I fixed the issue with work-around by hiding modal on Alert OK press. Anyway thanks a lot!

It worked on android but not on iOS. Please suggest some solution.

@zhongwuzw

This comment has been minimized.

Copy link
Collaborator

@zhongwuzw zhongwuzw commented Jul 16, 2019

Hi guys, I think we may fixed it on latest master branch, if you guys tried it which not worked, please file a new issue.

@TechSatya

This comment has been minimized.

Copy link

@TechSatya TechSatya commented Jul 19, 2019

Using of "AlertIOS" component for iOS helped me to avoid this issue.

The workaround is as below;

AlertIOS.alert(
  'Alert Title', 'Alert message',
    [
      {
        text: 'OK', onPress: () => this.setState({ loading: false})
      }
    ]
);
@cristianoccazinsp

This comment has been minimized.

Copy link

@cristianoccazinsp cristianoccazinsp commented Jul 19, 2019

@TechSatya are you confident about this? One would guess that Alert uses AlertIOS behind the scenes.

@TechSatya

This comment has been minimized.

Copy link

@TechSatya TechSatya commented Jul 19, 2019

Yes, @cristianoccazinsp I think this is the only possible solution as of now because the other availed solution didn't help me in any way. As from the last 2 days I was stuck in this issue, I started giving a try to the "AlertIOS" component and fortunately found it successful.

Yes, Alerts uses AlertIOS behind it, but don't know how it got successful? Maybe something lacks in implementing of AlertIOS in Alert behind the scenes.

To be more specific to the code for both platforms;

(Platform.OS === 'android' ? Alert : AlertIOS).alert(
  'Alert Title', 'Alert message',
    [
      {
        text: 'OK', onPress: () => this.setState({ loading: false})
      }
    ]
);
@fengyouchao

This comment has been minimized.

Copy link

@fengyouchao fengyouchao commented Jul 22, 2019

Using setTimeout is NOT a safe way to avoid this problem. I recommend using onDismiss props in iOS to do something after the modal closed (including Alert some messages). I created a class named ModalView to replace RN Modal class.

class ModalView extends React.Component {

    state = {
        visible: false
    };

    close({then} = {}) {
        if (Platform.OS === 'ios') {
            this.setState({visible: false, onDismiss: then});
        } else {
            this.setState({visible: false});
            if (then !== undefined) {
                then();
            }
        }
    }

    show() {
        this.setState({visible: true});
    }

    render() {
        return (
            <Modal
                visible={this.state.visible}
                onDismiss={this.state.onDismiss}
                {...this.props}>
                {this.props.children}
            </Modal>
        )
    }
}

Using

Just replace your Modal with ModalView and add ref props.

<ModalView ref={ref=>this.modalView=ref} 
   //other Modal props
>
//your components
<ModalView>

Show Modal

this.modalView.show();

Close Modal

this.modalView.close();

Alert some messages after the modal closed.

this.modalView.close({
      then: () => {
          Alert.alert('Hello World');
          //your code
      }
});
@1612844

This comment has been minimized.

Copy link

@1612844 1612844 commented Aug 4, 2019

I have same issue here when i use "react-native": "0.59.9" and "react-native-modal": "^11.3.1"

And my solution is show the alert in Modal onDismiss props

@giautm

This comment has been minimized.

Copy link

@giautm giautm commented Sep 9, 2019

Agree with @fengyouchao, your solution was working well. Thank you.

@hoanglm4

This comment has been minimized.

Copy link

@hoanglm4 hoanglm4 commented Dec 5, 2019

I think facebook engineering need fix this bug.

@adimshev

This comment has been minimized.

Copy link

@adimshev adimshev commented Dec 8, 2019

You can use my solution (prevent opening Modal when Alert is opened, and open it after Alert was closed, using redux and hooks).

My solution is not full, later I will send solution that prevents opening many Modals at same time and prevents opening Alert while Modal is closing (based on queue and store subscribe).

In any case, you can refine my idea.

Modal + Alert.zip

@teledemic

This comment has been minimized.

Copy link

@teledemic teledemic commented Dec 16, 2019

FWIW a modification to @fengyouchao's workaround if you are using async/await is

async Close() {
	return new Promise((resolve, _reject) => {
		this.setState({ visible: false, onDismiss: resolve });
	});
}

Then you can just await this.modalView.Close();

@jbenzshawel

This comment has been minimized.

Copy link

@jbenzshawel jbenzshawel commented Jan 7, 2020

Still an issue with RN 0.61.2 - does anyone if this is fixed in any later 0.61 patch releases?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.