I'm tying to store the theme state in the app, so that the chosen theme will be persistent after the app is closed. I have two files, one is the App.js file which has the navigation, and the other is the DrawerContent.js file that has the content of the drawer as well as the switch for the theme. toggleTheme
is passed to the DrawerContent
through useContext
.
These are the snippets of the App file.
import {
NavigationContainer,
DefaultTheme as NavigationDefaultTheme,
DarkTheme as NavigationDarkTheme
} from '@react-navigation/native';
import {
Provider as PaperProvider,
DefaultTheme as PaperDefaultTheme,
DarkTheme as PaperDarkTheme
} from 'react-native-paper';
import AsyncStorage from '@react-native-community/async-storage';
const THEME_KEY = 'theme_color';
export default function App() {
const [isDarkTheme, setIsDarkTheme] = useState(false);
{/* Themes */ }
const CustomDefaultTheme = {
...NavigationDefaultTheme,
...PaperDefaultTheme,
colors: {
...NavigationDefaultTheme.colors,
...PaperDefaultTheme.colors,
background: '#ffffff',
text: '#333333',
tab: '#0789DC'
}
}
const CustomDarkTheme = {
...NavigationDarkTheme,
...PaperDarkTheme,
colors: {
...NavigationDarkTheme.colors,
...PaperDarkTheme.colors,
background: '#333333',
text: '#ffffff',
tab: '#2c3e50'
}
}
const theme = isDarkTheme ? CustomDarkTheme : CustomDefaultTheme;
// AsyncSotrage
const storeTheme = async (key, isDarkTheme) => {
try {
await AsyncStorage.setItem(THEME_KEY, JSON.stringify(isDarkTheme))
setIsDarkTheme(isDarkTheme);
console.log(isDarkTheme)
} catch (error) {
alert(error);
}
}
const getTheme = async () => {
try {
const savedTheme = await AsyncStorage.getItem(THEME_KEY)
if (savedTheme !== null) {
setIsDarkTheme(JSON.parse(savedTheme));
}
} catch (error) {
alert(error);
}
}
const authContext = useMemo(() => ({
toggleTheme: () => {
setIsDarkTheme(isDarkTheme => !isDarkTheme);
// storeTheme(isDarkTheme => !isDarkTheme);
console.log(isDarkTheme);
}
}),
[]
);
useEffect(() => {
getTheme();
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let userToken;
try {
userToken = await AsyncStorage.getItem(USER_TOKEN)
if (userToken !== null) {
setUserToken(JSON.parse(userToken))
}
} catch (e) {
alert(e)
}
// After restoring token, we may need to validate it in production apps
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
};
bootstrapAsync();
}, []);
return (
<PaperProvider theme={theme}>
<AuthContext.Provider value={authContext}>
<NavigationContainer theme={theme}>
...
</NavigationContainer>
</AuthContext.Provider>
</PaperProvider>
)
}
This is the DrawerContent code.
import {
useTheme,
Avatar,
Title,
Caption,
Paragraph,
Drawer,
Text,
TouchableRipple,
Switch
} from 'react-native-paper';
export function DrawerContent(props) {
const paperTheme = useTheme();
const { signOut, toggleTheme } = React.useContext(AuthContext);
return (
<View style={{ flex: 1 }}>
<DrawerContentScrollView>
<View style={styles.drawerContent}>
...
<Drawer.Section title="Preferences">
<TouchableRipple onPress={() => { toggleTheme() }}>
<View style={styles.preference}>
<Text>Dark Theme</Text>
<View pointerEvents="none">
<Switch
value={paperTheme.dark}
/>
</View>
</View>
</TouchableRipple>
</Drawer.Section>
</View>
</DrawerContentScrollView>
</View>
)
}
Perhaps the effective synchronous access of AsyncStorage can solve your problem. It is recommended that you use the react-native-easy-app open source library react-native-easy-app, through which you can access any data in AsyncStorage like memory objects.
For specific usage, maybe you can refer to the StorageController file in Project Sample_Hook