mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Appearance: Lazily Initialize NativeAppearance (#46123)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46123 Optimizes initialization performance by changing `Appearance` to lazily import `NativeAppearance` and setup its listeners. Changelog: [General][Changed] - Improve `Appearance` performance overhead by lazily initializing the NativeModule Reviewed By: rickhanlonii Differential Revision: D61578726 fbshipit-source-id: 13fe6de7b5c3b52b8f4c54dd567bbe146379cf0f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
fdb77ae924
commit
b86e8ef95f
+62
-30
@@ -8,37 +8,64 @@
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {EventSubscription} from '../vendor/emitter/EventEmitter';
|
||||
import type {AppearancePreferences, ColorSchemeName} from './NativeAppearance';
|
||||
import typeof INativeAppearance from './NativeAppearance';
|
||||
|
||||
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
|
||||
import EventEmitter, {
|
||||
type EventSubscription,
|
||||
} from '../vendor/emitter/EventEmitter';
|
||||
import EventEmitter from '../vendor/emitter/EventEmitter';
|
||||
import {isAsyncDebugging} from './DebugEnvironment';
|
||||
import NativeAppearance, {
|
||||
type AppearancePreferences,
|
||||
type ColorSchemeName,
|
||||
} from './NativeAppearance';
|
||||
import invariant from 'invariant';
|
||||
|
||||
const eventEmitter = new EventEmitter<{
|
||||
change: [{colorScheme: ?ColorSchemeName}],
|
||||
}>();
|
||||
|
||||
type NativeAppearanceEventDefinitions = {
|
||||
appearanceChanged: [AppearancePreferences],
|
||||
type Appearance = {
|
||||
colorScheme: ?ColorSchemeName,
|
||||
};
|
||||
|
||||
// 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;
|
||||
let lazyState: ?{
|
||||
+NativeAppearance: INativeAppearance,
|
||||
// Cache the color scheme to reduce the cost of reading it between changes.
|
||||
// NOTE: If `NativeAppearance` is null, this will always be null.
|
||||
appearance: ?Appearance,
|
||||
// NOTE: This is non-nullable to make it easier for `onChangedListener` to
|
||||
// return a non-nullable `EventSubscription` value. This is not the common
|
||||
// path, so we do not have to over-optimize it.
|
||||
+eventEmitter: EventEmitter<{change: [Appearance]}>,
|
||||
};
|
||||
|
||||
if (NativeAppearance != null) {
|
||||
new NativeEventEmitter<NativeAppearanceEventDefinitions>(
|
||||
NativeAppearance,
|
||||
).addListener('appearanceChanged', (newAppearance: AppearancePreferences) => {
|
||||
const colorScheme = toColorScheme(newAppearance.colorScheme);
|
||||
appearance = {colorScheme};
|
||||
eventEmitter.emit('change', appearance);
|
||||
});
|
||||
/**
|
||||
* Ensures that all state and listeners are lazily initialized correctly.
|
||||
*/
|
||||
function getState(): $NonMaybeType<typeof lazyState> {
|
||||
if (lazyState != null) {
|
||||
return lazyState;
|
||||
}
|
||||
const eventEmitter = new EventEmitter<{change: [Appearance]}>();
|
||||
// NOTE: Avoid initializing `NativeAppearance` until it is actually used.
|
||||
const NativeAppearance = require('./NativeAppearance').default;
|
||||
if (NativeAppearance == null) {
|
||||
// Assign `null` to avoid re-initializing on subsequent invocations.
|
||||
lazyState = {
|
||||
NativeAppearance: null,
|
||||
appearance: null,
|
||||
eventEmitter,
|
||||
};
|
||||
} else {
|
||||
const state: $NonMaybeType<typeof lazyState> = {
|
||||
NativeAppearance,
|
||||
appearance: null,
|
||||
eventEmitter,
|
||||
};
|
||||
new NativeEventEmitter<{
|
||||
appearanceChanged: [AppearancePreferences],
|
||||
}>(NativeAppearance).addListener('appearanceChanged', newAppearance => {
|
||||
state.appearance = {
|
||||
colorScheme: toColorScheme(newAppearance.colorScheme),
|
||||
};
|
||||
eventEmitter.emit('change', state.appearance);
|
||||
});
|
||||
lazyState = state;
|
||||
}
|
||||
return lazyState;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,15 +82,17 @@ export function getColorScheme(): ?ColorSchemeName {
|
||||
}
|
||||
}
|
||||
let colorScheme = null;
|
||||
const state = getState();
|
||||
const {NativeAppearance} = state;
|
||||
if (NativeAppearance != null) {
|
||||
if (appearance == null) {
|
||||
// Lazily initialize `appearance`. This should only happen once because
|
||||
// we never reassign a null value to `appearance`.
|
||||
appearance = {
|
||||
if (state.appearance == null) {
|
||||
// Lazily initialize `state.appearance`. This should only
|
||||
// happen once because we never reassign a null value to it.
|
||||
state.appearance = {
|
||||
colorScheme: toColorScheme(NativeAppearance.getColorScheme()),
|
||||
};
|
||||
}
|
||||
colorScheme = appearance.colorScheme;
|
||||
colorScheme = state.appearance.colorScheme;
|
||||
}
|
||||
return colorScheme;
|
||||
}
|
||||
@@ -72,9 +101,11 @@ export function getColorScheme(): ?ColorSchemeName {
|
||||
* Updates the current color scheme to the supplied value.
|
||||
*/
|
||||
export function setColorScheme(colorScheme: ?ColorSchemeName): void {
|
||||
const state = getState();
|
||||
const {NativeAppearance} = state;
|
||||
if (NativeAppearance != null) {
|
||||
NativeAppearance.setColorScheme(colorScheme ?? 'unspecified');
|
||||
appearance = {colorScheme};
|
||||
state.appearance = {colorScheme};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +115,7 @@ export function setColorScheme(colorScheme: ?ColorSchemeName): void {
|
||||
export function addChangeListener(
|
||||
listener: ({colorScheme: ?ColorSchemeName}) => void,
|
||||
): EventSubscription {
|
||||
const {eventEmitter} = getState();
|
||||
return eventEmitter.addListener('change', listener);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user