๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“ฑ Cross Platform/React Native

[React Native] AsyncStorage ์‚ฌ์šฉํ•ด ๋””๋ฐ”์ด์Šค์— ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ(Store data on a device using AsyncStorage)

by Fomagran ๐Ÿ’ป 2022. 6. 18.
728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š” Foma ์ž…๋‹ˆ๋‹ค!

 

์˜ค๋Š˜์€ ์ €๋ฒˆ ์‹œ๊ฐ„์— ๋‹ค๋ค˜๋˜ List ํ™”๋ฉด ์„ ๊ธฐ๋ฐ˜์œผ๋กœ AsyncStorage๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฐ”๋กœ ์‹œ์ž‘ํ• ๊ฒŒ์š”~

 

์–ธ์–ด๋Š” TypeScript, ํ™˜๊ฒฝ์€ Expo๋กœ ์ง„ํ–‰ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!


AsyncStorage๋ž€?

 

์•”ํ˜ธํ™” ๋˜์ง€ ์•Š์€ ๋น„๋™๊ธฐ์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” Key-Value ์ €์žฅ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

 

์•ฑ ์ „์—ญ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, LocalStorage ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 


Deprecated?

 

React Native ๊ณต์‹ ๋ฌธ์„œ์— Deprecated ๋ผ๊ณ  ๋˜์–ด ์žˆ์–ด '๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฑด๊ฐ€..?'

 

ํ•˜๊ณ  ๊ตฌ๊ธ€๋ง์„ ํ•ด๋ดค๋”๋‹ˆ ์›๋ž˜๋Š” React Native ์ž์ฒด์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง€์›ํ–ˆ๋Š”๋ฐ์š”.

 

 

์ด์ œ๋Š” ์ž์ฒด ์ง€์›์„ ์ค‘๋‹จํ•˜๊ณ  community packages์— ์˜คํ”ˆ ์†Œ์Šค๋กœ ๋งŒ๋“ค์–ด์ง„ AsyncStorage๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


Install

 

๊ทธ ์ค‘ ๊ฐ€์žฅ ๋งŽ์€ ์‚ฌ๋žŒ์ด ์‚ฌ์šฉํ•˜๋Š” AsyncStorage ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

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

 

GitHub - react-native-async-storage/async-storage: An asynchronous, persistent, key-value storage system for React Native.

An asynchronous, persistent, key-value storage system for React Native. - GitHub - react-native-async-storage/async-storage: An asynchronous, persistent, key-value storage system for React Native.

github.com


AsyncService.ts

 

AsyncStorage๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ , ๋ฐ›์•„์˜ค๊ณ , ์‚ญ์ œํ•˜๋Š” ํ•จ์ˆ˜๋“ค์„ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๊ฐ€์žฅ ๋จผ์ € ์œ„์—์„œ ์„ค์น˜ํ•œ async storage ๋ชจ๋“ˆ์„ import ํ•ด์ค๋‹ˆ๋‹ค.

 

import AsyncStorage from "@react-native-async-storage/async-storage";

 

Store data

 

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

 

์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ JSON์œผ๋กœ ๋œ value๋ฅผ JSON.stringfy ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ string์œผ๋กœ ๋ฐ”๊ฟ”์ค๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  AsyncStorage์— ์›ํ•˜๋Š” key์™€ ํ•จ๊ป˜ stringValue๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

 

export const storeData = async (key: string, value: any) => {
  try {
    const stringValue = JSON.stringify(value);
    await AsyncStorage.setItem(key, stringValue);
  } catch (e: any) {
    console.error(e.message);
  }
};

 

Get data

 

๊ทธ ๋‹ค์Œ์œผ๋ก  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ํ•จ์ˆ˜์ธ๋ฐ์š”.

 

์œ„์—์„œ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์—์„œ ์›ํ•˜๋Š” key๊ฐ’์„ ์ง€์ •ํ•ด ์ค€ ๋’ค ๊ฐ’์„ ์ €์žฅํ–ˆ์ฃ ?

 

๊ณ ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋• ํ•ด๋‹น key๊ฐ’์„ ๋„ฃ์–ด์ฃผ๊ณ  JSON.parse ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ string์œผ๋กœ ๋œ JSON ํ˜•ํƒœ์˜ ๋ฌธ์žฅ์„ ์˜ค๋ธŒ์ ํŠธ ํ˜•์‹์— ๋งž๊ฒŒ ๋ฐ”๊ฟ”์ค๋‹ˆ๋‹ค.

 

export const getData = async (key: string) => {
  try {
    const value = await AsyncStorage.getItem(key);
    if (value !== null) {
      const data = JSON.parse(value);
      return data;
    }
  } catch (e: any) {
    console.log(e.message);
  }
};

 

Remove data

 

๊ทธ ๋‹ค์Œ์œผ๋ก  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋–„์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ key๊ฐ’์„ ์ด์šฉํ•ด ํ•ด๋‹นํ•˜๋Š” value๊ฐ’์„ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

export const removeData = async (key: string) => {
  try {
    await AsyncStorage.removeItem(key);
  } catch (e: any) {
    console.error(e.message);
  }
};

 

Contains key

 

๊ทธ ๋‹ค์Œ์œผ๋ก  ํ•ด๋‹น key๊ฐ€ AsyncStorage ์•ˆ์— ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ธ๋ฐ์š”.

 

๋งŒ์•ฝ ํ•ด๋‹นํ•˜๋Š” key๊ฐ€ ์—†๋Š”๋ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ ค ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚˜๊ฒ ์ฃ ?

 

์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

export const containsKey = async (key: string) => {
  try {
    const keys = await AsyncStorage.getAllKeys();
    return keys.includes(key);
  } catch (e: any) {
    console.error(e.message);
  }
};

PersonService.ts

 

์ด์ œ ์œ„์—์„œ ๋งŒ๋“  AsyncService๋ฅผ ์ด์šฉํ•ด์„œ Person์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์‚ญ์ œํ•˜๊ณ  ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” Service๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  ํ•„์š”ํ•œ ๋ชจ๋“ˆ๋“ค์„ importํ•ด ์ค๋‹ˆ๋‹ค.

 

import { containsKey, getData, removeData, storeData } from "./AsyncService";
import data from "../data/personData.json";
import { Person } from "../models/Person";

 

Init Person

 

๊ฐ€์žฅ ๋จผ์ € Person์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ์š”.

 

์œ„์—์„œ ๋งŒ๋“ค์–ด ์ค€ containsKey๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋งŒ์•ฝ ์—†๋‹ค๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ด๊ฒƒ์€ ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š”๋ฐ, ๋˜ ์ €์žฅํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

export const initPersons = async (): Promise<boolean> => {
  const hasPersons = await containsKey("person-data");

  if (!hasPersons) {
    await storeData("person-data", data);
    return true;
  }

  return false;
};

 

Get persons

 

key๋ฅผ ์ด์šฉํ•˜์—ฌ Person ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

 

์ด ๋•Œ ์ฃผ์˜ํ•  ์ ์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ธ๋ฅด ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์„ Promise๋กœ ํ•ด์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

export const getPersons = async (): Promise<Person[]> => {
  const persons = await getData("person-data");
  return persons;
};

 

Remove all persons

 

๋งŒ์•ฝ ํ•ด๋‹น key์— ์žˆ๋Š” ๋ชจ๋“  Person ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

 

export const removeAllPersons = async () => {
  await removeData("person-data");
};

useCachedResources.ts

 

์บ์‹œ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด useState์™€ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ initPersons()๋ฅผ ์‹คํ–‰ํ•ด ์ค๋‹ˆ๋‹ค.

 

import { useEffect, useState } from "react";
import * as Font from "expo-font";
import { initPersons } from "../storage/PersonService";

export default function useCachedResources() {
  const [isLoadingComplete, setIsLoadingComplete] = useState(false);

  useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        await initPersons();
      } catch (e) {
        console.warn(e);
      } finally {
        setIsLoadingComplete(true);
      }
    }

    loadResourcesAndDataAsync();
  }, [isLoadingComplete]);

  return isLoadingComplete;
}

Init Person Data

 

์ด์ œ App์„ ์ฒ˜์Œ ์‹คํ–‰ํ–ˆ์„ ๋•Œ Person ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

App.tsx

 

์œ„์—์„œ ๋งŒ๋“  useCahedResources๋ฅผ ์ด์šฉํ•˜์—ฌ ๋งŒ์•ฝ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ณ  ์•„๋‹ˆ๋ผ๋ฉด null์ด ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 

export default function App() {
  const isLoaded = useCachedResources();

  if (isLoaded) {
    return (
      <>
        <Navigation />
      </>
    );
  } else {
    return null;
  }
}

Person List

 

PersonListScreen์œผ๋กœ ๋Œ์•„์™€์„œ useState์™€ useEffect๋ฅผ ์‚ฌ์šฉํ•ด์„œ getPerson์œผ๋กœ Person ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.

 

export default function PersonListScreen({
  navigation,
}: NativeStackHeaderProps) {
  const [persons, setPersons] = useState<Person[]>([]);

  useEffect(() => {
    async function getData() {
      const _persons = await getPersons();
      setPersons(_persons);
    }
    getData();
  }, []);
  ...

 

ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ FlatList์˜ data์— ์ ์šฉํ•ด ์ค๋‹ˆ๋‹ค.

 

 return (
    <View style={styles.container}>
      <FlatList
        data={persons}
        renderItem={({ item }: { item: Person }) => {
          return (
            ...
            )
  );

์‹คํ–‰ ํ™”๋ฉด

 

ํ™”๋ฉด์„ ์‹คํ–‰์‹œ์ผœ ๋ณด๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜ ์ €์žฅ๋˜์–ด ๋ณด์—ฌ์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€