Skip to content

Commit d85d5d2

Browse files
kkoudevfacebook-github-bot
authored andcommitted
Fix cannot working Modal's onDismiss. (#29882)
Summary: Fixes: #29455 Modal's onDismiss is not called on iOS. This issue occurred the commit bd2b7d6 and was fixed the commit 27a3248. However, the master and stable-0.63 branches do not have this modified commit applied to them. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Modal's onDismiss prop will now be called successfully. Pull Request resolved: #29882 Test Plan: Tested on iOS with this change: 1. Set function Modal's onDismiss prop. 1. Set Modal's visible props is true. (show Modal) 1. Set Modal's visible props is false. (close Modal) 1. The set function in onDismiss is called. Reviewed By: shergin Differential Revision: D24648412 Pulled By: hramos fbshipit-source-id: acf28fef21420117c845d3aed97e47b5dd4e9390
1 parent 4700075 commit d85d5d2

File tree

7 files changed

+113
-20
lines changed

7 files changed

+113
-20
lines changed

Libraries/Modal/Modal.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
const AppContainer = require('../ReactNative/AppContainer');
1414
const I18nManager = require('../ReactNative/I18nManager');
15+
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
16+
import NativeModalManager from './NativeModalManager';
17+
const Platform = require('../Utilities/Platform');
1518
const React = require('react');
1619
const ScrollView = require('../Components/ScrollView/ScrollView');
1720
const StyleSheet = require('../StyleSheet/StyleSheet');
@@ -26,6 +29,11 @@ import type {DirectEventHandler} from '../Types/CodegenTypes';
2629
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
2730
import RCTModalHostView from './RCTModalHostViewNativeComponent';
2831

32+
const ModalEventEmitter =
33+
Platform.OS === 'ios' && NativeModalManager != null
34+
? new NativeEventEmitter(NativeModalManager)
35+
: null;
36+
2937
/**
3038
* The Modal component is a simple way to present content above an enclosing view.
3139
*
@@ -161,9 +169,22 @@ class Modal extends React.Component<Props> {
161169
this._identifier = uniqueModalIdentifier++;
162170
}
163171

172+
componentDidMount() {
173+
if (ModalEventEmitter) {
174+
this._eventSubscription = ModalEventEmitter.addListener(
175+
'modalDismissed',
176+
event => {
177+
if (event.modalID === this._identifier && this.props.onDismiss) {
178+
this.props.onDismiss();
179+
}
180+
},
181+
);
182+
}
183+
}
184+
164185
componentWillUnmount() {
165-
if (this.props.onDismiss != null) {
166-
this.props.onDismiss();
186+
if (this._eventSubscription) {
187+
this._eventSubscription.remove();
167188
}
168189
}
169190

Libraries/Modal/RCTModalHostViewNativeComponent.js

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
1515
import type {
1616
WithDefault,
1717
DirectEventHandler,
18+
BubblingEventHandler,
1819
Int32,
1920
} from '../Types/CodegenTypes';
2021

@@ -86,6 +87,14 @@ type NativeProps = $ReadOnly<{|
8687
*/
8788
onShow?: ?DirectEventHandler<null>,
8889

90+
/**
91+
* The `onDismiss` prop allows passing a function that will be called once
92+
* the modal has been dismissed.
93+
*
94+
* See https://reactnative.dev/docs/modal.html#ondismiss
95+
*/
96+
onDismiss?: ?BubblingEventHandler<null>,
97+
8998
/**
9099
* Deprecated. Use the `animationType` prop instead.
91100
*/

React/Views/RCTModalHostViewManager.m

+9-18
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import "RCTBridge.h"
1111
#import "RCTModalHostView.h"
1212
#import "RCTModalHostViewController.h"
13+
#import "RCTModalManager.h"
1314
#import "RCTShadowView.h"
1415
#import "RCTUtils.h"
1516

@@ -46,8 +47,6 @@ - (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex
4647

4748
@interface RCTModalHostViewManager () <RCTModalHostViewInteractor>
4849

49-
@property (nonatomic, copy) dispatch_block_t dismissWaitingBlock;
50-
5150
@end
5251

5352
@implementation RCTModalHostViewManager {
@@ -79,33 +78,25 @@ - (void)presentModalHostView:(RCTModalHostView *)modalHostView
7978
if (_presentationBlock) {
8079
_presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock);
8180
} else {
82-
__weak typeof(self) weakself = self;
8381
[[modalHostView reactViewController] presentViewController:viewController
8482
animated:animated
85-
completion:^{
86-
!completionBlock ?: completionBlock();
87-
__strong typeof(weakself) strongself = weakself;
88-
!strongself.dismissWaitingBlock
89-
?: strongself.dismissWaitingBlock();
90-
strongself.dismissWaitingBlock = nil;
91-
}];
83+
completion:completionBlock];
9284
}
9385
}
9486

9587
- (void)dismissModalHostView:(RCTModalHostView *)modalHostView
9688
withViewController:(RCTModalHostViewController *)viewController
9789
animated:(BOOL)animated
9890
{
91+
dispatch_block_t completionBlock = ^{
92+
if (modalHostView.identifier) {
93+
[[self.bridge moduleForClass:[RCTModalManager class]] modalDismissed:modalHostView.identifier];
94+
}
95+
};
9996
if (_dismissalBlock) {
100-
_dismissalBlock([modalHostView reactViewController], viewController, animated, nil);
97+
_dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock);
10198
} else {
102-
self.dismissWaitingBlock = ^{
103-
[viewController.presentingViewController dismissViewControllerAnimated:animated completion:nil];
104-
};
105-
if (viewController.presentingViewController) {
106-
self.dismissWaitingBlock();
107-
self.dismissWaitingBlock = nil;
108-
}
99+
[viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock];
109100
}
110101
}
111102

React/Views/RCTModalManager.h

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <UIKit/UIKit.h>
9+
10+
#import <React/RCTBridgeModule.h>
11+
#import <React/RCTEventEmitter.h>
12+
13+
@interface RCTModalManager : RCTEventEmitter <RCTBridgeModule>
14+
15+
- (void)modalDismissed:(NSNumber *)modalID;
16+
17+
@end

React/Views/RCTModalManager.m

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import "RCTModalManager.h"
9+
10+
@interface RCTModalManager ()
11+
12+
@property BOOL shouldEmit;
13+
14+
@end
15+
16+
@implementation RCTModalManager
17+
18+
RCT_EXPORT_MODULE();
19+
20+
- (NSArray<NSString *> *)supportedEvents
21+
{
22+
return @[ @"modalDismissed" ];
23+
}
24+
25+
- (void)startObserving
26+
{
27+
_shouldEmit = YES;
28+
}
29+
30+
- (void)stopObserving
31+
{
32+
_shouldEmit = NO;
33+
}
34+
35+
- (void)modalDismissed:(NSNumber *)modalID
36+
{
37+
if (_shouldEmit) {
38+
[self sendEventWithName:@"modalDismissed" body:@{@"modalID" : modalID}];
39+
}
40+
}
41+
42+
@end

ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/EventEmitters.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ void ModalHostViewEventEmitter::onShow(OnShow event) const {
129129
return payload;
130130
});
131131
}
132+
void ModalHostViewEventEmitter::onDismiss(OnDismiss event) const {
133+
dispatchEvent("dismiss", [event=std::move(event)](jsi::Runtime &runtime) {
134+
auto payload = jsi::Object(runtime);
135+
136+
return payload;
137+
});
138+
}
132139
void ModalHostViewEventEmitter::onOrientationChange(OnOrientationChange event) const {
133140
dispatchEvent("orientationChange", [event=std::move(event)](jsi::Runtime &runtime) {
134141
auto payload = jsi::Object(runtime);

ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/EventEmitters.h

+6
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ class ModalHostViewEventEmitter : public ViewEventEmitter {
196196

197197
};
198198

199+
struct OnDismiss {
200+
201+
};
202+
199203
enum class OnOrientationChangeOrientation {
200204
Portrait,
201205
Landscape
@@ -216,6 +220,8 @@ class ModalHostViewEventEmitter : public ViewEventEmitter {
216220

217221
void onShow(OnShow value) const;
218222

223+
void onDismiss(OnDismiss value) const;
224+
219225
void onOrientationChange(OnOrientationChange value) const;
220226
};
221227

0 commit comments

Comments
 (0)