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

Modal will appear once more when its mask is clicked. #4140

Open
Qyokizzzz opened this issue Oct 19, 2023 · 18 comments
Open

Modal will appear once more when its mask is clicked. #4140

Qyokizzzz opened this issue Oct 19, 2023 · 18 comments

Comments

@Qyokizzzz
Copy link

Current behaviour

Modal appears once more before close when its mask is clicked.

Expected behaviour

Modal disappears directly when its mask is clicked.

How to reproduce?

import * as React from 'react';
import { Modal, Portal, Text, Button, PaperProvider } from 'react-native-paper';

const MyComponent = () => {
  const [visible, setVisible] = React.useState(false);

  const showModal = () => setVisible(true);
  const hideModal = () => setVisible(false);
  const containerStyle = {backgroundColor: 'white', padding: 20};

  return (
    <PaperProvider>
      <Portal>
        <Modal visible={visible} onDismiss={hideModal} contentContainerStyle={containerStyle}>
          <Text>Example Modal.  Click outside this area to dismiss.</Text>
        </Modal>
      </Portal>
      <Button style={{marginTop: 30}} onPress={showModal}>
        Show
      </Button>
    </PaperProvider>
  );
};

export default MyComponent;

Preview

modal-bug.mp4

My suggestion

suggestion

The current behavior is expected by the test case, which prevents my changes from passing all tests.

$ jest Modal
 FAIL  src/components/__tests__/Modal.test.tsx
  Modal
    √ animated value changes correctly (81 ms)
    by default
      √ should render passed children (255 ms)
      √ should render a backdrop in default theme's color (14 ms)
      √ should render a custom backdrop color if specified (8 ms)
      √ should receive appropriate top and bottom insets (11 ms)
    when open
      if closed via touching backdrop
        × will run the animation but not fade out (57 ms)
        √ should invoke the onDismiss function after the animation (16 ms)
      if closed via Android back button
        √ will run the animation but not fade out (27 ms)
        × should invoke the onDismiss function after the animation (32 ms)
    when open as non-dismissible modal
      if closed via touching backdrop
        √ will run the animation but not fade out (15 ms)
        √ should not invoke onDismiss (13 ms)
      if closed via Android back button
        √ will run the animation but not fade out (14 ms)
        √ should not invoke onDismiss (11 ms)
    when visible prop changes
      from false to true (closed to open)
        √ should run fade-in animation on opening (12 ms)
      from true to false (open to closed)
        √ should run fade-out animation on closing (16 ms)
        √ should not invoke onDismiss (12 ms)
        √ should close even if the dialog is not dismissible (12 ms)
    when visible prop changes again during the open/close animation
      while closing, back to true (visible)
        √ should keep the modal open (23 ms)
      while opening, back to false (hidden)
        √ should keep the modal closed (20 ms)

  ● Modal › when open › if closed via touching backdrop › will run the animation but not fade out

    expect(element).toHaveStyle()

    - Expected

    - opacity: 1;
    + opacity: 0;

      123 |         });
      124 |
    > 125 |         expect(getByTestId('modal-backdrop')).toHaveStyle({
          |                                               ^
      126 |           opacity: 1,
      127 |         });
      128 |

      at Object.toHaveStyle (src/components/__tests__/Modal.test.tsx:125:47)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
      at node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
      at Object.<anonymous> (node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)

  ● Modal › when open › if closed via Android back button › should invoke the onDismiss function after the animation

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      210 |         });
      211 |
    > 212 |         expect(onDismiss).toHaveBeenCalledTimes(1);
          |                           ^
      213 |       });
      214 |     });
      215 |   });

      at Object.toHaveBeenCalledTimes (src/components/__tests__/Modal.test.tsx:212:27)

Test Suites: 1 failed, 1 total
Tests:       2 failed, 17 passed, 19 total
Snapshots:   0 total
Time:        1.789 s, estimated 2 s

Your Environment

software version
android 12
react-native 0.72.5
react-native-paper 5.10.4
node 18.12.1
yarn 1.22.19
@Qyokizzzz Qyokizzzz added the bug label Oct 19, 2023
@CXiann
Copy link

CXiann commented Oct 31, 2023

Is there any solution for this?

@Qyokizzzz
Copy link
Author

Is there any solution for this?

Modify the Modal source code, please refer to 'My suggestion' for details.

@lukewalczak
Copy link
Member

lukewalczak commented Nov 18, 2023

Hey @CXiann, I was trying to reproduce the issue, however without the success. Could you please attach the small github repo presenting the problem?

I was trying on:

react-native-paper: 5.10.4 and 5.11.1
react-native: 0.72.5
android: 12
new architecture: enabled and disabled

@raihanadfal
Copy link

im changed newArchEnabled to false on android/gradle.properties. and it's worked on me.

@dabakovich
Copy link

I have the same issue. The Modal "blinks" only when you're clicking outside the modal. But when I put a button inside a Modal and press it for close – it closes without a blink. It is not reproducing on iOS.

react-native-paper: 5.10.3
react-native: 0.72.4
New architecture enabled.
Android 10.

@nyagami
Copy link

nyagami commented Feb 15, 2024

I have the same issue.
I think because the hideModal was called twice. And if your tested in a good device with small code, the delay between 2 animations is too small for recognizing.

Try to test with higher duration.

image

@ErMapsh
Copy link

ErMapsh commented Feb 27, 2024

I tried dismissable={false} on Dialog component and its work like this <Dialog visible={visible} dismissable={false}> </Dialog>

@iM-GeeKy
Copy link

iM-GeeKy commented Oct 8, 2024

Experiencing the same issue on iOS when testing out with the new arch. Possibly related to new arch support.

...
"expo": "^51.0.36",
"react-native": "~0.75.3",
"react-native-paper": "^5.12.5",
...

Using patch-package and the suggestion from @Qyokizzzz works. I'll leave below for those who may need it.

diff --git a/node_modules/react-native-paper/src/components/Modal.tsx b/node_modules/react-native-paper/src/components/Modal.tsx
index 313ecee..8cc7d0f 100644
--- a/node_modules/react-native-paper/src/components/Modal.tsx
+++ b/node_modules/react-native-paper/src/components/Modal.tsx
@@ -141,6 +141,8 @@ function Modal({
     }).start();
   }, [opacity, scale]);
 
+  const shouldModalDisappearRef = React.useRef(true);
+
   const hideModal = React.useCallback(() => {
     Animated.timing(opacity, {
       toValue: 0,
@@ -152,15 +154,17 @@ function Modal({
         return;
       }
 
-      if (visible) {
+      if (visible && shouldModalDisappearRef?.current) {
         onDismissCallback();
       }
 
-      if (visibleRef.current) {
+      if (visibleRef.current && !shouldModalDisappearRef?.current) {
         showModal();
       } else {
         setRendered(false);
       }
+
+      shouldModalDisappearRef.current = true;
     });
   }, [onDismissCallback, opacity, scale, showModal, visible]);
 
@@ -171,6 +175,7 @@ function Modal({
 
     const onHardwareBackPress = () => {
       if (dismissable || dismissableBackButton) {
+        shouldModalDisappearRef.current = false;
         hideModal();
       }

@Jakub-Plan-d-k
Copy link

+1

@pitbred2
Copy link

The same problem with Menu, but Menu blinking twice when it's appears. Problem with Modal and Menu started when Expo SDK upgrade to 52.

@tamaroning
Copy link

same issue with expo 52 & iOS

@MarcLopezAvila
Copy link

Any fix?

@pitbred2
Copy link

pitbred2 commented Nov 16, 2024

Any fix?

Fix patch for Modal is above, no fix for Menu as I understand.

@pyrocreators
Copy link

same issue for IOS when updated to expo 52.0.6

@antomanc
Copy link

same bug here on Android

@codan84
Copy link

codan84 commented Dec 19, 2024

Also, any TextInput component inside Portal will flicker when being changed, reproduced here:
https://github.com/codan84/text-input-flicker

@SusulAdam
Copy link

same issue for IOS on expo 52.0.7

@SusulAdam
Copy link

@codan84 To fix it, you can use defaultValue instead of value prop in TextInput

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests