A handler function of Appearance.addChangeListener is triggered when the app goes to the background. It also has a wrong colorScheme value.
System:
OS: macOS 10.15.1
CPU: (4) x64 Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz
Memory: 92.24 MB / 16.00 GB
Shell: 5.7.1 - /bin/zsh
Binaries:
Node: 10.13.0 - /usr/local/bin/node
Yarn: 1.12.1 - /usr/local/bin/yarn
npm: 6.9.0 - /usr/local/bin/npm
Watchman: Not Found
Managers:
CocoaPods: 1.8.4 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
Android SDK:
API Levels: 23, 25, 26, 27, 28, 29
Build Tools: 27.0.3, 28.0.2, 28.0.3, 29.0.2
System Images: android-23 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
Android NDK: Not Found
IDEs:
Android Studio: 3.5 AI-191.8026.42.35.5791312
Xcode: 11.2.1/11B500 - /usr/bin/xcodebuild
Languages:
Python: 2.7.15 - /usr/local/bin/python
npmPackages:
@react-native-community/cli: Not Found
react: 16.11.0 => 16.11.0
react-native: 0.62.1 => 0.62.1
npmGlobalPackages:
*react-native*: Not Found
Appearance.addChangeListener at the root of the app (I use it with react-native-navigation).Appearance.addChangeListener(({ colorScheme }) => {
console.log(colorScheme);
});
No theme changed.
| :warning: | Missing Reproducible Example |
|---|---|
| :information_source: | It looks like your issue is missing a reproducible example. Please provide a Snack or a repository that demonstrates the issue you are reporting in a minimal, complete, and reproducible manner. |
Here is a repo: https://github.com/rosskhanas/react-native-appearance-bug
Once the app goes to the background it logs 2 rows - 2 different values to the console - light, and dark.
+1, having the same issue!
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.
Not stale
The problem is on iOS only.
When backgrounding the app, perhaps due to a bug on iOS 13 the user interface style changes to the opposite color scheme and then back to the current color scheme immediately afterwards. The best solution is to debounce the notification calls by 10ms like they did on react-native-appearance.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0,01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey: self.traitCollection,
}];
});
Definitely still seeing this. Moved to expo/react-native-appearance for now.
With this code in my App.js, I am seeing the extra calls but not the flash back and forth between themes:
const systemScheme = useColorScheme();
const themeObject = systemScheme === 'light' ? light : dark;
const toggleTheme = useCallback((colorScheme) => {
const statusBarTheme = colorScheme === 'light' ? 'dark' : 'light';
StatusBar.setBarStyle(`${statusBarTheme}-content`);
}, []);
useEffect(() => {
Appearance.addChangeListener(({ colorScheme }) => {
toggleTheme(colorScheme);
});
return () => {
Appearance.removeChangeListener();
};
}, [toggleTheme]);
Hope that helps someone.
I have the same problem on iOS, and I found expo/react-native-appearance have this issue too, I don't know if it was my mistake.
I fix it by Lodash temporary, I don't find a better way.
import _ from 'lodash';
useEffect(() => {
const handleColorModeChange = async (preferences: Appearance.AppearancePreferences) => {
console.log(preferences.colorScheme);
// do your job ....
};
// delay 1 second to handle change
Appearance.addChangeListener(_.throttle(handleColorModeChange, 1000, {
leading: false,
trailing: true
}));
return () => {
Appearance.removeChangeListener(handleColorModeChange);
};
}, []);
@Macrow your workaround helped. thank you
here it is as a hook to use in lieu of the rn useColorScheme hook. I also used setTimeout instead of throttle
```typescript jsx
import { Appearance, ColorSchemeName } from 'react-native';
import { useEffect, useRef, useState } from 'react';
export default function useColorScheme(delay = 500): NonNullable
const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());
let timeout = useRef
useEffect(() => {
Appearance.addChangeListener(onColorSchemeChange);
return () => {
resetCurrentTimeout();
Appearance.removeChangeListener(onColorSchemeChange);
};
}, []);
function onColorSchemeChange(preferences: Appearance.AppearancePreferences) {
resetCurrentTimeout();
timeout = setTimeout(() => {
setColorScheme(preferences.colorScheme);
}, delay);
}
function resetCurrentTimeout() {
if (timeout) {
clearTimeout(timeout);
}
}
return colorScheme as NonNullable
}
```
Most helpful comment
+1, having the same issue!