์๋ ํ์ธ์ 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
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 (
...
)
);
์คํ ํ๋ฉด
ํ๋ฉด์ ์คํ์์ผ ๋ณด๋ฉด ํด๋น ๋ฐ์ดํฐ๊ฐ ์ ์ ์ฅ๋์ด ๋ณด์ฌ์ง๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๋๊ธ