How do I store and get the theme state using AsyncStorage

819 Views Asked by At

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>
  )
}
1

There are 1 best solutions below

0
On

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