-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Appearance addChangeListener handler is called when app goes to background with wrong color scheme #28525
Comments
|
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 - |
+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.
|
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:
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
|
@Macrow your workaround helped. thank you here it is as a hook to use in lieu of the rn import { Appearance, ColorSchemeName } from 'react-native';
import { useEffect, useRef, useState } from 'react';
export default function useColorScheme(delay = 500): NonNullable<ColorSchemeName> {
const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());
let timeout = useRef<NodeJS.Timeout | null>(null).current;
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<ColorSchemeName>;
} |
Thanks @jasonaibrahim, I really didn't want to fool with this nonsense today. That makes it easy! 🙌 |
Dump question, isn't it the easiest way to just call const initAppearanceListener = () => {
const listener: Appearance.AppearanceListener = ({ colorScheme } /* <-- ignore */) => {
setColorScheme(Appearance.getColorScheme());
};
Appearance.addChangeListener(listener);
return () => Appearance.removeChangeListener(listener);
}; |
@mrsimply you could, although I'm not sure what ignoring the colorScheme that's sent in really buys. Are you not seeing the listener fired twice with the wrong and then correct color scheme when the app is backgrounded? I definitely do, so for now have just been ignoring the colorScheme listener calls when AppState says things are backgrounded. |
This worked for me, just ignoring the argument passed into the function |
I believe this is a feature on iOS 13 and above. It does this to take screenshots of the app for the App Switcher in case color scheme changes. |
Sorry, but as I say in the following link, it keeps happening very randomly with your workaround: |
@komik966 Very glad that you asked! I thought it would, and it almost did, but there were two minor cases where the
App.Switcher.MP4At the end, I chose to use the same color for the borders under both light and dark mode to avoid the flashing when going to the app switcher. |
Experiencing flashing with useColorScheme hook as well.. "react-native": "0.70.4", |
Try to use |
2 years passed and this bug still haunted me every other day |
this worked for me: import { useEffect, useState } from "react";
import { Appearance, ColorSchemeName } from "react-native";
import debounce from "lodash/debounce";
// This hook is from https://github.com/facebook/react-native/issues/28525
export function useColorScheme(): NonNullable<ColorSchemeName> {
const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());
const initAppearanceListener = () => {
const listener: Appearance.AppearanceListener = debounce(
() => {
setColorScheme(Appearance.getColorScheme());
},
200,
{ leading: false, trailing: true }
);
const changeListener = Appearance.addChangeListener(listener);
return () => changeListener.remove();
};
useEffect(() => {
initAppearanceListener();
}, []);
return colorScheme as NonNullable<ColorSchemeName>;
} |
I solved it finally using AppState 🎉.
Let me know if it doesn't work! |
See facebook/react-native#28525 for more details.
See facebook/react-native#28525 for more details.
2023, latest version, and this bug is still there. |
wow how is this bug still not fixed. i remember having this same bug in flutter, but there the issue was tagged, reproed, triaged, and fixed in less than 12 hours. anyway, thanks for the many and varied workarounds. |
It's kind of sad how many persistent bugs just sit for years without much notice. Oh well... :/ |
Imho, you could argue if it is a bug or not, since the behavior follows the underlying iOS framework behavior. However, it does feel as unwanted behavior. That being said, it is easily remediated by just checking if the change happens in the foreground. In our codebase we just query the current AppState in the listener and only if it is equal to "foreground" we act upon it. |
But if someone changes their dark mode in the settings while the app is in background mode, it won't track. At least the last time I tried it wouldn't work. I would love to see your implementation if you wouldn't mind. |
Hi all, did you try this solution #28525 (comment) ? This seems the best solution which also updates app screenshot in the app switcher. |
I'm using react navigation (which they indicated was incompatible) |
Maybe I'm missing something here, but I just ignore listener calls when the app is backgrounded and manually check the current system theme when the app becomes active. I guess that won't cover the screenshot change in the app switcher until they re-launch the app, but ¯(ツ)/¯ |
My workaround (https://github.com/ds300/patch-package use for applying changes) diff --git a/node_modules/react-native/React/CoreModules/RCTAppearance.mm b/node_modules/react-native/React/CoreModules/RCTAppearance.mm
index 17535a9..e7fd131 100644
--- a/node_modules/react-native/React/CoreModules/RCTAppearance.mm
+++ b/node_modules/react-native/React/CoreModules/RCTAppearance.mm
@@ -106,9 +106,8 @@ RCT_EXPORT_METHOD(setColorScheme : (NSString *)style)
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme)
{
- if (_currentColorScheme == nil) {
- _currentColorScheme = RCTColorSchemePreference(nil);
- }
+ _currentColorScheme = RCTColorSchemePreference(nil);
+
return _currentColorScheme;
} |
how many devs experience this issue in the latest version of react-native? |
This was fixed for me on 0.73.5! 🎉 |
I'm using version |
that's great! Given that there are a couple of reports of the issue being fixed let's close this. If you have any further issues I would recommend opening a new issue with a proper repro. |
2024 not working for me :( |
Description
A handler function of
Appearance.addChangeListener
is triggered when the app goes to the background. It also has a wrongcolorScheme
value.React Native version:
Steps To Reproduce
Appearance.addChangeListener
at the root of the app (I use it with react-native-navigation).Expected Results
No theme changed.
The text was updated successfully, but these errors were encountered: