From 6118aff69d69dce557b1c9d217c538f5670afed1 Mon Sep 17 00:00:00 2001 From: Alan Hughes Date: Mon, 25 Sep 2023 20:00:41 -0700 Subject: [PATCH] fix: over reporting trait changes (#39439) Summary: Closes https://github.com/facebook/react-native/issues/35972 Closes https://github.com/facebook/react-native/issues/36713 This PR addresses a couple of issues with `useColorScheme` and the `Appearance` API. - https://github.com/facebook/react-native/issues/38214 introduced a regression. Using to `RCTExecuteOnMainQueue` was a mistake as we need this to happen synchronously to return the result. Doing it async causes the `traitCollection` to remain uninitialized. - The `useColorScheme` hook is updating when the app is in the background on iOS and the OS is taking the snapshots for the app switcher. This causes a flash when returning to the app as the correct color is set again. Here, we can check for the app state in `traitCollectionDidChange` and not send these events when in the background. - Removed a line that was left over after some OS version checks were removed when support for iOS 12 was dropped. ## Changelog: [IOS] [FIXED] - Don't send the `RCTUserInterfaceStyleDidChangeNotification` when the app is in the background. Pull Request resolved: https://github.com/facebook/react-native/pull/39439 Test Plan: Tested on `rn-tester`, logged the changes whenever `useColorScheme` updates. It no longer happens when the app is in the background. The returned interface style on the initial render is always correct now. Reviewed By: NickGerleman Differential Revision: D49454281 Pulled By: javache fbshipit-source-id: 87e24158a49c50608c79e73fb484442f5aad36a6 --- .../react-native/React/Base/RCTRootView.m | 3 ++ .../React/CoreModules/RCTAppearance.h | 1 + .../React/CoreModules/RCTAppearance.mm | 29 ++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/react-native/React/Base/RCTRootView.m b/packages/react-native/React/Base/RCTRootView.m index c7c142075bbc6a..5acd5f03c4c951 100644 --- a/packages/react-native/React/Base/RCTRootView.m +++ b/packages/react-native/React/Base/RCTRootView.m @@ -368,6 +368,9 @@ - (void)contentViewInvalidated - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; + if (RCTSharedApplication().applicationState == UIApplicationStateBackground) { + return; + } [[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification diff --git a/packages/react-native/React/CoreModules/RCTAppearance.h b/packages/react-native/React/CoreModules/RCTAppearance.h index caa842d72f6a1b..9909ca9e741d7d 100644 --- a/packages/react-native/React/CoreModules/RCTAppearance.h +++ b/packages/react-native/React/CoreModules/RCTAppearance.h @@ -17,4 +17,5 @@ RCT_EXTERN NSString *RCTCurrentOverrideAppearancePreference(); RCT_EXTERN NSString *RCTColorSchemePreference(UITraitCollection *traitCollection); @interface RCTAppearance : RCTEventEmitter +- (instancetype)init; @end diff --git a/packages/react-native/React/CoreModules/RCTAppearance.mm b/packages/react-native/React/CoreModules/RCTAppearance.mm index 2930401fc98f6e..449ff0396be889 100644 --- a/packages/react-native/React/CoreModules/RCTAppearance.mm +++ b/packages/react-native/React/CoreModules/RCTAppearance.mm @@ -57,11 +57,7 @@ void RCTOverrideAppearancePreference(NSString *const colorSchemeOverride) return RCTAppearanceColorSchemeLight; } - traitCollection = traitCollection ?: [UITraitCollection currentTraitCollection]; return appearances[@(traitCollection.userInterfaceStyle)] ?: RCTAppearanceColorSchemeLight; - - // Default to light on older OS version - same behavior as Android. - return RCTAppearanceColorSchemeLight; } @interface RCTAppearance () @@ -71,6 +67,19 @@ @implementation RCTAppearance { NSString *_currentColorScheme; } +- (instancetype)init +{ + if ((self = [super init])) { + UITraitCollection *traitCollection = RCTSharedApplication().delegate.window.traitCollection; + _currentColorScheme = RCTColorSchemePreference(traitCollection); + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appearanceChanged:) + name:RCTUserInterfaceStyleDidChangeNotification + object:nil]; + } + return self; +} + RCT_EXPORT_MODULE(Appearance) + (BOOL)requiresMainQueueSetup @@ -100,9 +109,6 @@ - (dispatch_queue_t)methodQueue RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme) { - if (_currentColorScheme == nil) { - _currentColorScheme = RCTColorSchemePreference(nil); - } return _currentColorScheme; } @@ -129,14 +135,15 @@ - (void)appearanceChanged:(NSNotification *)notification - (void)startObserving { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(appearanceChanged:) - name:RCTUserInterfaceStyleDidChangeNotification - object:nil]; } - (void)stopObserving { +} + +- (void)invalidate +{ + [super invalidate]; [[NSNotificationCenter defaultCenter] removeObserver:self]; }