Skip to content

Commit 0ac3df3

Browse files
authored
fix(react): avoid multiple invocations of onDidDismiss and onWillPresent (#28020)
Issue number: Resolves #28010 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> `onDidDismiss` and `onWillPresent` will fire twice when having a manual binding in your implementation for inline overlays. e.g.: ```tsx <IonAlert onDidDismiss={() => console.log('hello world')} /> ``` Will result in: > hello world > hello world ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - `onDidDismiss` and `onWillPresent` do not execute the callback handler twice per invocation ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev-build: `7.3.1-dev.11692305436.16a4008f`
1 parent 5a1bbc9 commit 0ac3df3

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

packages/react/src/components/createInlineOverlayComponent.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ export const createInlineOverlayComponent = <PropType, ElementType>(
6363

6464
componentDidUpdate(prevProps: IonicReactInternalProps<PropType>) {
6565
const node = this.ref.current! as HTMLElement;
66-
attachProps(node, this.props, prevProps);
66+
/**
67+
* onDidDismiss and onWillPresent have manual implementations that
68+
* will invoke the original handler. We need to filter those out
69+
* so they don't get attached twice and called twice.
70+
*/
71+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
72+
const { onDidDismiss, onWillPresent, ...cProps } = this.props;
73+
attachProps(node, cProps, prevProps);
6774
}
6875

6976
componentWillUnmount() {

packages/react/test/base/src/pages/overlay-components/ActionSheetComponent.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import React from 'react';
21
import { IonButton, IonContent, IonPage, IonActionSheet } from '@ionic/react';
3-
import { useState } from 'react';
2+
import React, { useState } from 'react';
43

54
const ActionSheetComponent: React.FC = () => {
65
const [message, setMessage] = useState('');
76
const [show, setShow] = useState(false);
7+
const [willPresentCount, setWillPresentCount] = useState(0);
8+
const [didDismissCount, setDidDismissCount] = useState(0);
89

910
return (
1011
<IonPage>
@@ -26,7 +27,13 @@ const ActionSheetComponent: React.FC = () => {
2627
},
2728
]}
2829
header="Action Sheet"
29-
onDidDismiss={() => setShow(false)}
30+
onWillPresent={() => {
31+
setWillPresentCount(willPresentCount + 1);
32+
}}
33+
onDidDismiss={() => {
34+
setDidDismissCount(didDismissCount + 1);
35+
setShow(false);
36+
}}
3037
/>
3138
<IonButton expand="block" onClick={() => setShow(true)}>
3239
Show ActionSheet
@@ -41,6 +48,8 @@ const ActionSheetComponent: React.FC = () => {
4148
Show ActionSheet, hide after 250 mss
4249
</IonButton>
4350
<div>{message}</div>
51+
<div>onWillPresent count: {willPresentCount}</div>
52+
<div>onDidDismiss count: {didDismissCount}</div>
4453
</IonContent>
4554
</IonPage>
4655
);

packages/react/test/base/tests/e2e/specs/overlay-components/IonActionSheet.cy.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@ describe('IonActionSheet', () => {
1717
});
1818

1919
it('display action and call dismiss to close it', () => {
20-
//show action sheet
20+
cy.get('ion-content').contains('onWillPresent count: 0');
21+
cy.get('ion-content').contains('onDidDismiss count: 0');
22+
23+
// show action sheet
2124
cy.get('ion-button').contains('Show ActionSheet, hide after 250 ms').click();
2225
cy.get('ion-action-sheet').contains('Action Sheet');
2326

24-
//verify action sheet is hidden
27+
// verify action sheet is hidden
2528
cy.get('ion-action-sheet').should('not.be.visible');
29+
30+
// verify lifecycle events are called once
31+
cy.get('ion-content').contains('onWillPresent count: 1');
32+
cy.get('ion-content').contains('onDidDismiss count: 0');
2633
});
34+
2735
});

0 commit comments

Comments
 (0)