AsyncStorage와 MMKV — 로컬 데이터 저장소 비교
AsyncStorage는 React Native의 localStorage이고, MMKV는 그보다 30배 빠른 네이티브 저장소입니다.
앱을 종료해도 유지되어야 하는 데이터(토큰, 설정, 온보딩 여부 등)를 저장할 때 로컬 저장소가 필요합니다.
AsyncStorage
npm install @react-native-async-storage/async-storage
import AsyncStorage from '@react-native-async-storage/async-storage';
// 저장
await AsyncStorage.setItem('username', '홍길동');
// 객체 저장 (직렬화 필요)
await AsyncStorage.setItem('user', JSON.stringify({ id: 1, name: '홍길동' }));
// 읽기
const username = await AsyncStorage.getItem('username');
const user = JSON.parse(await AsyncStorage.getItem('user') ?? '{}');
// 삭제
await AsyncStorage.removeItem('username');
// 여러 항목 동시 처리
await AsyncStorage.multiSet([
['token', 'abc123'],
['refreshToken', 'xyz789'],
]);
const [[, token], [, refreshToken]] = await AsyncStorage.multiGet([
'token',
'refreshToken',
]);
// 전체 삭제
await AsyncStorage.clear();
커스텀 Hook
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(initialValue);
const [loaded, setLoaded] = useState(false);
useEffect(() => {
AsyncStorage.getItem(key).then((stored) => {
if (stored !== null) setValue(JSON.parse(stored));
setLoaded(true);
});
}, [key]);
const setStoredValue = useCallback(async (newValue: T | ((prev: T) => T)) => {
setValue((prev) => {
const resolved = typeof newValue === 'function'
? (newValue as (prev: T) => T)(prev)
: newValue;
AsyncStorage.setItem(key, JSON.stringify(resolved));
return resolved;
});
}, [key]);
return [value, setStoredValue, loaded] as const;
}
// 사용
function SettingsScreen() {
const [isDark, setIsDark, loaded] = useLocalStorage('darkMode', false);
if (!loaded) return <ActivityIndicator />;
return <Switch value={isDark} onValueChange={setIsDark} />;
}
MMKV
npm install react-native-mmkv
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
// 동기적으로 동작 — await 불필요!
storage.set('username', '홍길동');
storage.set('count', 42);
storage.set('isLoggedIn', true);
// 읽기
const username = storage.getString('username');
const count = storage.getNumber('count');
const isLoggedIn = storage.getBoolean('isLoggedIn');
// 객체 저장
storage.set('user', JSON.stringify({ id: 1, name: '홍길동' }));
const user = JSON.parse(storage.getString('user') ?? '{}');
// 삭제
storage.delete('username');
// 전체 키 목록
const keys = storage.getAllKeys();
// 키 존재 여부
const exists = storage.contains('username');
// 전체 삭제
storage.clearAll();
AsyncStorage vs MMKV 비교
| 항목 | AsyncStorage | MMKV |
|---|---|---|
| 동작 방식 | 비동기 (await 필요) | ** 동기** (즉시 반환) |
| 속도 | 느림 | ~30배 빠름 |
| 데이터 타입 | 문자열만 | 문자열, 숫자, Boolean |
| 암호화 | 없음 | 지원 |
| Expo 지원 | O | EAS Build 필요 |
| 설치 난이도 | 낮음 | 중간 |
성능 차이가 큽니다. AsyncStorage는 Bridge를 통해 비동기로 동작하지만, MMKV는 JSI를 통해 동기적으로 네이티브 메모리에 직접 접근합니다. 토큰 확인처럼 앱 시작 시 빠르게 읽어야 하는 데이터에는 MMKV가 유리합니다.
Zustand + MMKV Persist
import { create } from 'zustand';
import { persist, createJSONStorage, StateStorage } from 'zustand/middleware';
import { MMKV } from 'react-native-mmkv';
const mmkvStorage = new MMKV();
// MMKV를 Zustand storage로 사용
const zustandMMKVStorage: StateStorage = {
setItem: (name, value) => mmkvStorage.set(name, value),
getItem: (name) => mmkvStorage.getString(name) ?? null,
removeItem: (name) => mmkvStorage.delete(name),
};
const useSettingsStore = create(
persist(
(set) => ({
isDarkMode: false,
language: 'ko',
toggleDarkMode: () => set((s) => ({ isDarkMode: !s.isDarkMode })),
}),
{
name: 'settings',
storage: createJSONStorage(() => zustandMMKVStorage),
}
)
);
어떤 걸 선택해야 하나?
- **Expo 프로젝트, 간단한 저장 **: AsyncStorage
- ** 성능이 중요한 경우 **: MMKV
- ** 암호화가 필요한 민감 데이터 **: MMKV (암호화 옵션)
- ** 앱 시작 시 동기적 읽기 필요 **: MMKV
정리
- AsyncStorage는 ** 비동기 **, MMKV는 ** 동기 **로 동작합니다
- MMKV는 JSI 기반으로 ** 약 30배 빠른** 성능을 제공합니다
- 상태관리 라이브러리의 persist 미들웨어 와 함께 사용하면 앱 재시작 후에도 상태가 유지됩니다
- 보안이 필요한 데이터(토큰 등)는 MMKV 암호화 또는 react-native-keychain 을 사용하세요
댓글 로딩 중...