PURE React Native의 비동기 스토리지

PURE React Native와 Async Storage를 통합하는 방법을 알아보겠습니다.

1단계: 비동기 스토리지 설치



먼저 다음 명령을 사용하여 비동기 저장소를 설치하겠습니다.

npm i @react-native-async-storage/async-storage


비동기 스토리지는 로컬 스토리지와 비슷하지만 앱용인 반면 로컬 스토리지는 웹용입니다.

2단계: 비동기 스토리지를 사용한 CRUD




비동기 저장소(도우미 파일)



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;


3단계: 사용 방법?




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


React Native 구성 요소에서 Redux와 함께 사용하는 방법은 무엇입니까?

// ___________________ 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)


NEXT 블로그는 5월 27일까지 제공됩니다.

무엇 향후 계획?



1. PURE React Native로 스크롤하기



2. Pure React Native를 사용한 프로젝트



3. 앱 개발에 대한 추가 정보



4. 플레이스토어에 배포하는 방법



5. JavaScript/TypeScript를 사용한 미친 짓



6. 모든 서버에 대한 자동화된 테스트 작성



7. Expo로 XP 없이 Android 앱을 만드는 방법



(apk 생성 포함)

의심의 여지가 있습니까?



의견을 남기거나 Twitter에서 @SilveLEAF로 연락하거나

나에 대해 더 알고 싶어? 여기와!
SilvenLEAF.github.io

좋은 웹페이지 즐겨찾기