From 92f8f7ad6bb538c4e5cae7b7106417f59ece1f19 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 20 Aug 2024 21:49:54 -0700 Subject: [PATCH] Appearance: Cache `colorScheme` in JavaScript (#46122) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46122 Implements a JavaScript cache for `colorScheme` in the `Appearance` module, so that we avoid potentially expensive and unnecessary native property accesses. Changelog: [General][Changed] - Improved `Appearance.getColorScheme` performance Reviewed By: rickhanlonii Differential Revision: D61567880 --- .../Libraries/Utilities/Appearance.js | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/react-native/Libraries/Utilities/Appearance.js b/packages/react-native/Libraries/Utilities/Appearance.js index f8d31a10cd4260..eff658e9017370 100644 --- a/packages/react-native/Libraries/Utilities/Appearance.js +++ b/packages/react-native/Libraries/Utilities/Appearance.js @@ -27,12 +27,17 @@ type NativeAppearanceEventDefinitions = { appearanceChanged: [AppearancePreferences], }; +// Cache the color scheme to reduce the cost of reading it between changes. +// NOTE: If `NativeAppearance` is null, this will always be null. +let appearance: ?{colorScheme: ?ColorSchemeName} = null; + if (NativeAppearance != null) { new NativeEventEmitter( NativeAppearance, ).addListener('appearanceChanged', (newAppearance: AppearancePreferences) => { const colorScheme = toColorScheme(newAppearance.colorScheme); - eventEmitter.emit('change', {colorScheme}); + appearance = {colorScheme}; + eventEmitter.emit('change', appearance); }); } @@ -49,14 +54,28 @@ export function getColorScheme(): ?ColorSchemeName { return 'light'; } } - return toColorScheme(NativeAppearance?.getColorScheme()); + let colorScheme = null; + if (NativeAppearance != null) { + if (appearance == null) { + // Lazily initialize `appearance`. This should only happen once because + // we never reassign a null value to `appearance`. + appearance = { + colorScheme: toColorScheme(NativeAppearance.getColorScheme()), + }; + } + colorScheme = appearance.colorScheme; + } + return colorScheme; } /** * Updates the current color scheme to the supplied value. */ export function setColorScheme(colorScheme: ?ColorSchemeName): void { - NativeAppearance?.setColorScheme(toColorScheme(colorScheme) ?? 'unspecified'); + if (NativeAppearance != null) { + NativeAppearance.setColorScheme(colorScheme ?? 'unspecified'); + appearance = {colorScheme}; + } } /**