I am trying a setup , So that when I change my System theme my react native app theme should also change. I have use react navigation and react-native-appearance. On app startup correct system theme is applied, But when I change theme while using app for first time it doesn't. But When I try to change system theme for second time it also changes app theme and works correctly.
here is my code :-
App.js
import React from 'react';
import {} from 'react-native';
import {AppearanceProvider} from 'react-native-appearance';
import Main from './main';
export default function App() {
return (
<AppearanceProvider>
<Main/>
</AppearanceProvider>
);
}
Main.js
import React, { useState,useEffect } from 'react';
import {} from 'react-native';
import {Appearance} from 'react-native-appearance';
import {DarkTheme,DefaultTheme,NavigationContainer} from '@react-navigation/native';
import Home from './home';
const myDarkTheme={
...DarkTheme,
colors:{
...DarkTheme.colors,
text:"#fff",
statusBarColor:"#000"
}
};
const myLightTheme={
...DefaultTheme,
colors:{
...DefaultTheme.colors,
text:"#000",
statusBarColor:"rgb(242, 242, 242)"
}
};
export default function Main(){
const [theme,setTheme]=useState();
console.log(theme);
const onThemeChange=()=>{
const newColor=Appearance.getColorScheme();
setTheme(newColor);
}
useEffect(()=>{
onThemeChange()
const subscription=Appearance.addChangeListener(()=>{
onThemeChange()
})
return ()=>subscription.remove();
},[])
return(
<NavigationContainer theme={theme === 'light' ? myLightTheme : myDarkTheme}>
<Home/>
</NavigationContainer>
)
}
And Home.js
import React from 'react';
import { StyleSheet, Text, View,StatusBar } from 'react-native';
import {useTheme} from '@react-navigation/native';
export default function Home(){
const {colors}=useTheme();
return (
<View style={{...styles.container,backgroundColor:colors.background}}>
<Text style={{color:colors.text}}>Open up App.js to start working on your app!</Text>
<StatusBar barStyle={colors.statusBarColor==='#000' ? 'light-content':'dark-content'} backgroundColor={colors.background}/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
Please help me So that theme Changes for first time also when I change system theme for first time after app startup.
I am trying a setup , So that when I change my System theme my react native app theme should also change. I have use react navigation and react-native-appearance. On app startup correct system theme is applied, But when I change theme while using app for first time it doesn't. But When I try to change system theme for second time it also changes app theme and works correctly.
here is my code :-
App.js
import React from 'react';
import {} from 'react-native';
import {AppearanceProvider} from 'react-native-appearance';
import Main from './main';
export default function App() {
return (
<AppearanceProvider>
<Main/>
</AppearanceProvider>
);
}
Main.js
import React, { useState,useEffect } from 'react';
import {} from 'react-native';
import {Appearance} from 'react-native-appearance';
import {DarkTheme,DefaultTheme,NavigationContainer} from '@react-navigation/native';
import Home from './home';
const myDarkTheme={
...DarkTheme,
colors:{
...DarkTheme.colors,
text:"#fff",
statusBarColor:"#000"
}
};
const myLightTheme={
...DefaultTheme,
colors:{
...DefaultTheme.colors,
text:"#000",
statusBarColor:"rgb(242, 242, 242)"
}
};
export default function Main(){
const [theme,setTheme]=useState();
console.log(theme);
const onThemeChange=()=>{
const newColor=Appearance.getColorScheme();
setTheme(newColor);
}
useEffect(()=>{
onThemeChange()
const subscription=Appearance.addChangeListener(()=>{
onThemeChange()
})
return ()=>subscription.remove();
},[])
return(
<NavigationContainer theme={theme === 'light' ? myLightTheme : myDarkTheme}>
<Home/>
</NavigationContainer>
)
}
And Home.js
import React from 'react';
import { StyleSheet, Text, View,StatusBar } from 'react-native';
import {useTheme} from '@react-navigation/native';
export default function Home(){
const {colors}=useTheme();
return (
<View style={{...styles.container,backgroundColor:colors.background}}>
<Text style={{color:colors.text}}>Open up App.js to start working on your app!</Text>
<StatusBar barStyle={colors.statusBarColor==='#000' ? 'light-content':'dark-content'} backgroundColor={colors.background}/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
Please help me So that theme Changes for first time also when I change system theme for first time after app startup.
Share Improve this question asked Aug 4, 2020 at 9:10 NamanNaman 801 silver badge9 bronze badges 1- Have you found a solution? – Paul Commented Nov 30, 2020 at 12:42
5 Answers
Reset to default 6modify the MainActivity.java
import android.content.res.Configuration; // <--- import
// copy these lines
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactInstanceManager().onConfigurationChanged(this, newConfig);
}
According to the docs Appearence.addChangeListener, is provided with the callback function which has colorScheme. You can use that to update the state directly, no need to call the onThemeChange() function again.
useEffect(()=>{
onThemeChange();
const subscription = Appearance.addChangeListener(({ colorScheme }) => {
setTheme(colorScheme);
})
return () => subscription.remove();
},[])
There's an open issue,
https://github./facebook/react-native/issues/28823
If you are using react-native then you can merge in the branch someone has provided on the above issue to fix it. But I am using Expo.
It's worthwile to mention that, in case you are using a chrome based debugger the theme always will be light. Either disable debugging or switch the debugger.
https://github./facebook/react-native/issues/28823#issuement-640671784
I was having the same problem with the hook only returning 'light', no matter how much I'd toggle the appearance in the simulator.
After a lot of digging into code, it turned out the reason it was doing this was due to - the debugger! If you're using a Chrome-based debugger (either in browser or using the standalone RN debugger) the Appearance module will always return light, due to the debugger not being able to handle async functions (or something like that, it was a few days ago!).
I can't say I understand the idiosyncracies as to why it does this, but the upshot of it all is I stopped using the Chrome debugger and moved to flipper - and it worked! I'm now able to swap between dark and light mode using the useColorTheme hook as expected.
Hope this helps someone else, it was a head scratcher for me for quite a while!
For class ponent
import React from "react";
import {
SafeAreaView,
Text,
View,
Dimensions,
StyleSheet,
TouchableHighlight,
Image,
ImageBackground,
TextInput,
TouchableOpacity,
ScrollView,
KeyboardAvoidingView,
FlatList,
Appearance,
Animated,
} from "react-native";
constructor(props) {
super(props);
this.state = {
theme: false,
};
}
ponentDidMount() {
Appearance.getColorScheme() == "dark"
? this.setState({ theme: true })
: this.setState({ theme: false })
}
ponentDidUpdate() {
this.subscription=Appearance.addChangeListener((theme) => {
// console.log("theme", theme);
theme.colorScheme == "dark"
? this.setState({ theme: true })
: this.setState({ theme: false });
});
}
ponentWillUnmount() {
this.subscription.remove();
}
render() {
return (
<View
style={[
{
padding: 1,
flex: 1,
},
{ backgroundColor: this.state.theme == true ? "#000" : "#fff" },
]}
>
)}
For functional ponent
const [theme, setTheme] = useState(false);
useEffect(() => {
themeCheck();
}, []);
const themeCheck = async () => {
const getScheme = await Appearance.getColorScheme();
getScheme == "dark" ? setTheme(true) : setTheme(false);
};
useEffect(() => {
const subscription = Appearance.addChangeListener((theme) => {
// console.log("theme", theme);
theme.colorScheme == "dark" ? setTheme(true) : setTheme(false);
});
return () => subscription.remove();
},[])
return (
<>
{/* <StatusBar barStyle="light-content" */}
<SafeAreaView
style={[
styles.containerview1,
{ backgroundColor:theme == true ? "#000" : "#fff" },
]}
></SafeAreaView></>)