DEV Community

Cover image for Async Storage in PURE React Native
SilvenLEAF
SilvenLEAF

Posted on

4 3

Async Storage in PURE React Native

Let's learn how to integrate Async Storage with PURE React Native.

Step 1: Install async storage

First let's install async storage with the following command

npm i @react-native-async-storage/async-storage
Enter fullscreen mode Exit fullscreen mode

Async storage is similar to Local storage but it is meant for the apps whereas Local storage is for the web.

Step 2: CRUD with async storage

Async Store (Helper file)
import AsyncStorage from "@react-native-async-storage/async-storage";

// Storing Data
const storeData = async (storageKey: string, value: any) => {
  try {
    const jsonValue = typeof value === 'string' ? value : JSON.stringify(value);
    await AsyncStorage.setItem(storageKey, jsonValue);

    return { msg: `Saving successful` };
  } catch (error) {
    // saving error
    console.log(error);
    return { error: true, msg: `Saving failed` };
  }
}

// Getting Data
const getStringValue = async (storageKey: string) => {
  try {
    const value = await AsyncStorage.getItem(storageKey)
    return value
  } catch (error) {
    // error reading value
    console.log(error);
  }
}
const getObjectValue = async (storageKey: string) => {
  try {
    const jsonValue = await AsyncStorage.getItem(storageKey)
    return jsonValue !== null ? JSON.parse(jsonValue) : null;
  } catch (error) {
    // error reading value
    console.log(error);
  }
}

// Updating Data
const updateObjectData = async (storageKey: string, value: any) => {
  try {
    const jsonValue = typeof value === 'string' ? value : JSON.stringify(value);
    await AsyncStorage.mergeItem!(storageKey, jsonValue);

    const newData = typeof value === 'string' ? await getStringValue(storageKey) : await getObjectValue(storageKey);

    return { msg: `Updating successful`, data: newData };
  } catch (error) {
    // updating error
    console.log(error);
    return { error: true, msg: `Updating failed` };
  }
}
const upsertObjectData = async (storageKey: string, value: any) => {
  try {
    const jsonValue = typeof value === 'string' ? value : JSON.stringify(value);
    const oldValue = await AsyncStorage.getItem(storageKey);

    if (oldValue === null) {
      await storeData(storageKey, value);
    } else {
      await AsyncStorage.mergeItem!(storageKey, jsonValue);
    }

    const newData = typeof value === 'string' ? await getStringValue(storageKey) : await getObjectValue(storageKey);

    return { msg: `Updating successful`, data: newData };
  } catch (error) {
    // upserting error
    console.log(error);
    return { error: true, msg: `Updating failed` };
  }
}

// Remove Data
const removeData = async (storageKey: string) => {
  try {

    await AsyncStorage.removeItem(storageKey);
    return { msg: `Removing successful` };

  } catch (error) {
    // removing error
    console.log(error);
    return { error: true, msg: `Removing failed` };
  }
}


// MUTLI FUNCS
const multiGetData = async (storageKeys: string[]) => {
  try {

    const valuesArray = await AsyncStorage.multiGet(storageKeys)
    return valuesArray;

  } catch (error) {
    // multi getting error
    console.log(error)
  }
}
const multiSetData = async (keyValueArray: [string,string][]) => {
  try {
    /*
      keyValueAray: [
       ["@MyApp_user", "value_1"],
       ["@MyApp_user", "value_1"]
     ]
    */
    const valuesArray = await AsyncStorage.multiSet(keyValueArray)
    return valuesArray;

  } catch (error) {
    console.log(error)
  }
}
const multiUpdateData = async (keyValueArray: [string,string][], value: any) => {
  try {
    /*
      keyValueAray: [
       ["@MyApp_user", "value_1"],
       ["@MyApp_user", "value_1"]
     ]
    */

    await AsyncStorage.multiMerge!(keyValueArray);
    const keys = keyValueArray.map(item => item[0]);
    const newMultiData = await multiGetData(keys);

    return { msg: `Updating successful`, data: newMultiData };
  } catch (error) {
    // multi updating error
    console.log(error);
    return { error: true, msg: `Updating failed` };
  }
}
const multiRemoveData = async (storageKeys: string[]) => {
  try {

    await AsyncStorage.multiRemove(storageKeys)
    return { msg: `Removing successful` };

  } catch (error) {
    // multi removing error
    console.log(error);
    return { error: true, msg: `Removing failed` };
  }
}

// SPECIALS
const getAllStorageKeys = async () => {
  try {

    const keys = await AsyncStorage.getAllKeys()
    return keys;

  } catch (error) {
    // read key error
    console.log(error)
  }
}
const clearStore = async () => {
  try {
    await AsyncStorage.clear();
    return { msg: `Store clearing successful` };
  } catch (error) {
    // clearing error
    console.log(error);
    return { error: true, msg: `Store clearing failed` };
  }
}

export const AsyncStoreKeyMap = {
  appSettings: 'appSettings',
  userProfile: 'userProfile',
  userProgress: 'userProgress',
}

const AsyncStore = {
  storeData,
  getStringValue, getObjectValue,
  updateObjectData, upsertObjectData,
  removeData,

  multiSetData,
  multiGetData,
  multiUpdateData,
  multiRemoveData,

  getAllStorageKeys,
  clearStore,
};

export default AsyncStore;
Enter fullscreen mode Exit fullscreen mode

Step 3: How to use?

import AsyncStore, { AsyncStoreKeyMap } from '../../../utils/AsyncStore';

AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { themeColor: color });
AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { isDarkTheme: !props.isDarkTheme });
AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { isSoundOn: !props.isSoundOn });
Enter fullscreen mode Exit fullscreen mode

How to use with Redux in a React Native Component?

// ___________________ root
import React from 'react';
import { connect } from 'react-redux';
import { NavigationProp } from '@react-navigation/native';

// ___________________ helpers
import Toast from 'react-native-toast-message';
import { rootVariables } from '../../rootStyles/variables';

// ___________________ async store
import AsyncStore, { AsyncStoreKeyMap } from '../../../utils/AsyncStore';

// ___________________ redux store
import { IRootState } from '../../store/store';
import { IAppSettingState } from '../../store/reducers/appSettingsReducer';

import appSettingsActions from '../../store/actions/appSettingsAction';
import userProgressActions from '../../store/actions/userProgressAction';



interface propsInterface extends IAppSettingState {
  navigation: NavigationProp<any>,
  app: {
    updateThemeColor: typeof appSettingsActions.updateThemeColor,
    updateIsDarkTheme: typeof appSettingsActions.updateIsDarkTheme,
    updateIsVibrationOn: typeof appSettingsActions.updateIsVibrationOn,
    updateIsSoundOn: typeof appSettingsActions.updateIsSoundOn,
    resetDefault: typeof appSettingsActions.resetDefault,
  },
  progress: {
    updateRank: typeof userProgressActions.updateRank,
    updateLevel: typeof userProgressActions.updateLevel,
    updateXP: typeof userProgressActions.updateXP,
    resetDefault: typeof userProgressActions.resetDefault,
  },
}



function SettingScreen(props: propsInterface) {
  const updateThemeColor = async (color: string) => {
    props.app.updateThemeColor(color);
    AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { themeColor: color });
  }

  const updateIsDarkTheme = async () => {
    props.app.updateIsDarkTheme(!props.isDarkTheme);
    AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { isDarkTheme: !props.isDarkTheme });
  }

  const updateIsSoundOn = async () => {
    props.app.updateIsSoundOn(!props.isSoundOn);
    AsyncStore.upsertObjectData(AsyncStoreKeyMap.appSettings, { isSoundOn: !props.isSoundOn });
  }


  const handleResetDefault = () => {
    props.app.resetDefault();
    AsyncStore.removeData(AsyncStoreKeyMap.appSettings);

    Toast.show({
      type: 'success',
      text1: 'Restore Default Successful',
      text2: 'Restore all default settings',
      topOffset: rootVariables.toastTopOffset,

    })
  }

  const handleResetProgress = () => {
    props.progress.resetDefault();
    AsyncStore.removeData(AsyncStoreKeyMap.userProgress);

    Toast.show({
      type: 'success',
      text1: 'Reset Progress Successful',
      text2: 'Reset all of your progress',
      topOffset: rootVariables.toastTopOffset,
    })
  }

  return (
    <SettingScreen/>
  );
}


const mapStateToProps = (state: IRootState) => {
  return {
    ...state.app,
  }
}

const mapDispatchToProps = (dispatch: any) => {
  return {
    app: {
      updateThemeColor: (color: string) => dispatch(appSettingsActions.updateThemeColor(color)),
      updateIsDarkTheme: (isDarkTheme: boolean) => dispatch(appSettingsActions.updateIsDarkTheme(isDarkTheme)),
      updateIsVibrationOn: (isVibrationOn: boolean) => dispatch(appSettingsActions.updateIsVibrationOn(isVibrationOn)),
      updateIsSoundOn: (isSoundOn: boolean) => dispatch(appSettingsActions.updateIsSoundOn(isSoundOn)),
      resetDefault: () => dispatch(appSettingsActions.resetDefault()),
    },

    progress: {
      updateRank: (rank: string) => dispatch(userProgressActions.updateRank(rank)),
      updateLevel: (level: number) => dispatch(userProgressActions.updateLevel(level)),
      updateXP: (xp: number) => dispatch(userProgressActions.updateXP(xp)),
      resetDefault: () => dispatch(userProgressActions.resetDefault()),
    },
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(SettingScreen)
Enter fullscreen mode Exit fullscreen mode

NEXT blog is coming by May 27th

What's NEXT?

1. Scrolling with PURE React Native

2. Project with Pure React Native

3. More on App Development

4. How to deploy to playstore

5. Insane stuff with JavaScript/TypeScript

6. Writing Automated Tests for any Server

7. How to create an Android APP with NO XP with Expo

(including apk generating)

Got any doubt?

Drop a comment or Feel free to reach out to me @SilveLEAF on Twitter or Linkedin

Wanna know more about me? Come here!
SilvenLEAF.github.io

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (0)

Neon image

Next.js applications: Set up a Neon project in seconds

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Get started →

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, cherished by the supportive DEV Community. Coders of every background are encouraged to bring their perspectives and bolster our collective wisdom.

A sincere “thank you” often brightens someone’s day—share yours in the comments below!

On DEV, the act of sharing knowledge eases our journey and forges stronger community ties. Found value in this? A quick thank-you to the author can make a world of difference.

Okay