-
Notifications
You must be signed in to change notification settings - Fork 752
asBaseComponent: stale module-level colorScheme prevents re-render on scheme switch back #3945
Description
Description
asBaseComponent HOC captures colorScheme as a module-level constant at import time. Since BaseComponent extends React.PureComponent (via UIComponent), components mounted after a scheme change hold a stale state.colorScheme that matches the original scheme. When switching back to that original scheme, the appearanceListener guard (this.state.colorScheme !== colorScheme) evaluates to false, skipping setState and preventing re-render.
Related to
- Components
- Demo
- Docs
- Typings
Steps to reproduce
- App starts in light mode → module-level
colorSchemeis captured as'light' - Go to a settings/appearance screen and switch to dark mode → all RNUI components re-render correctly
- Navigate to any screen — new components mount during dark mode with
state.colorScheme = 'light'(stale module-level value) - Switch back to light mode →
Scheme.broadcastSchemeChange('light')fires - Stale components check
'light' !== 'light'→false→setStateis never called → no re-render
Expected behavior
All RNUI components (Text, View, Button, Switch, etc.) should re-render with the updated color scheme when switching in both directions (light → dark AND dark → light).
Actual behavior
Components mounted after the first scheme change do not re-render when switching back to the original scheme. They retain the previous scheme's colors (e.g., light gray text on a light background) because BaseComponent (a PureComponent) skips rendering — both props and state appear unchanged.
More Info
Code snippet
The bug is in src/commons/asBaseComponent.js:
// Line 8 — evaluated ONCE at module load, never updated
const colorScheme = Scheme.getSchemeType();
function asBaseComponent(WrappedComponent, options = {}) {
// BaseComponent extends UIComponent which extends React.PureComponent
class BaseComponent extends UIComponent {
state = {
error: false,
colorScheme // All instances get the stale module-level value
};
appearanceListener = colorScheme => {
// This guard fails for stale instances when switching back to the original scheme
if (this.state.colorScheme !== colorScheme) {
this.setState({ colorScheme });
}
};
}
}Fix — evaluate Scheme.getSchemeType() per instance instead of once at module level:
const EMPTY_MODIFIERS = {};
-const colorScheme = Scheme.getSchemeType();
function asBaseComponent(WrappedComponent, options = {}) {
class BaseComponent extends UIComponent {
state = {
error: false,
- colorScheme
+ colorScheme: Scheme.getSchemeType()
};Screenshots/Video
N/A — the visual symptom is dark-theme text colors (e.g., #C9D6DF) rendered on a light-theme background (#F0F5F9), causing text to blend/disappear.
Environment
- React Native version: 0.83
- React Native UI Lib version: 8.3.4
Affected platforms
- Android
- iOS
- Web