diff --git a/React/CoreModules/RCTActionSheetManager.mm b/React/CoreModules/RCTActionSheetManager.mm index ee3c7b69b444dd..f2559cae034285 100644 --- a/React/CoreModules/RCTActionSheetManager.mm +++ b/React/CoreModules/RCTActionSheetManager.mm @@ -126,6 +126,10 @@ - (void)presentViewController:(UIViewController *)alertController NSInteger index = 0; bool isCancelButtonIndex = false; + // The handler for a button might get called more than once when tapping outside + // the action sheet on iPad. RCTResponseSenderBlock can only be called once so + // keep track of callback invocation here. + __block bool callbackInvoked = false; for (NSString *option in buttons) { UIAlertActionStyle style = UIAlertActionStyleDefault; if ([destructiveButtonIndices containsObject:@(index)]) { @@ -139,7 +143,10 @@ - (void)presentViewController:(UIViewController *)alertController UIAlertAction *actionButton = [UIAlertAction actionWithTitle:option style:style handler:^(__unused UIAlertAction *action) { - callback(@[ @(localIndex) ]); + if (!callbackInvoked) { + callbackInvoked = true; + callback(@[ @(localIndex) ]); + } }]; if (isCancelButtonIndex) { [actionButton setValue:cancelButtonTintColor forKey:@"titleTextColor"];