|
| 1 | +--- |
| 2 | +title: FAQ |
| 3 | +--- |
| 4 | + |
| 5 | +# Frequently Asked Questions |
| 6 | + |
| 7 | +## General |
| 8 | + |
| 9 | +### How do I store objects, arrays, or other non-string values? |
| 10 | + |
| 11 | +AsyncStorage only stores strings. Serialize values with `JSON.stringify` before writing, and `JSON.parse` when reading: |
| 12 | + |
| 13 | +```typescript |
| 14 | +import {createAsyncStorage} from "@react-native-async-storage/async-storage"; |
| 15 | + |
| 16 | +const storage = createAsyncStorage("my-app"); |
| 17 | + |
| 18 | +// Storing an object |
| 19 | +const user = {name: "John", age: 30}; |
| 20 | +await storage.setItem("user", JSON.stringify(user)); |
| 21 | + |
| 22 | +// Reading it back |
| 23 | +const raw = await storage.getItem("user"); |
| 24 | +const user = raw ? JSON.parse(raw) : null; |
| 25 | +``` |
| 26 | + |
| 27 | +### Is there a way to use the old v2-style singleton? |
| 28 | + |
| 29 | +Yes. The default export is a backward-compatible v2 instance: |
| 30 | + |
| 31 | +```typescript |
| 32 | +import AsyncStorage from "@react-native-async-storage/async-storage"; |
| 33 | + |
| 34 | +await AsyncStorage.getItem("key"); |
| 35 | +``` |
| 36 | + |
| 37 | +This uses the same legacy API as v2, including `multiGet`, `multiSet`, etc. If you are starting a new integration, |
| 38 | +prefer `createAsyncStorage` instead. See the [Migration guide](migration-to-3.md) for the full API comparison. |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +## Integrations |
| 43 | + |
| 44 | +### Redux Persist |
| 45 | + |
| 46 | +The v3 `AsyncStorage` instance implements exactly the storage interface Redux Persist expects (`getItem`, `setItem`, |
| 47 | +`removeItem`), so you can pass an instance directly as the `storage` option: |
| 48 | + |
| 49 | +```typescript |
| 50 | +import {createAsyncStorage} from "@react-native-async-storage/async-storage"; |
| 51 | +import {persistReducer, persistStore} from "redux-persist"; |
| 52 | +import {combineReducers, createStore} from "redux"; |
| 53 | + |
| 54 | +const storage = createAsyncStorage("redux"); |
| 55 | + |
| 56 | +const persistConfig = { |
| 57 | + key: "root", |
| 58 | + storage, |
| 59 | +}; |
| 60 | + |
| 61 | +const rootReducer = combineReducers({ |
| 62 | + // your reducers |
| 63 | +}); |
| 64 | + |
| 65 | +const persistedReducer = persistReducer(persistConfig, rootReducer); |
| 66 | +const store = createStore(persistedReducer); |
| 67 | +const persistor = persistStore(store); |
| 68 | +``` |
| 69 | + |
| 70 | +!!! tip "Use default export for migration from v2" |
| 71 | +The default export (`import AsyncStorage from "..."`) implements the same interface and can be passed as `storage` too. |
| 72 | +It allows for gradual migration to v3. |
| 73 | + |
| 74 | +### TanStack Query |
| 75 | + |
| 76 | +TanStack Query's `@tanstack/query-async-storage-persister` package expects a storage object with `getItem`, `setItem`, |
| 77 | +and `removeItem`. The v3 AsyncStorage instance matches this interface directly: |
| 78 | + |
| 79 | +```jsx |
| 80 | +import {createAsyncStorage} from "@react-native-async-storage/async-storage"; |
| 81 | +import {createAsyncStoragePersister} from "@tanstack/query-async-storage-persister"; |
| 82 | +import {QueryClient} from "@tanstack/react-query"; |
| 83 | +import {PersistQueryClientProvider} from "@tanstack/react-query-persist-client"; |
| 84 | + |
| 85 | +const queryClient = new QueryClient({ |
| 86 | + defaultOptions: { |
| 87 | + queries: { |
| 88 | + gcTime: 1000 * 60 * 60 * 24, // 24 hours |
| 89 | + }, |
| 90 | + }, |
| 91 | +}); |
| 92 | + |
| 93 | +const storage = createAsyncStorage("tanstack-query"); |
| 94 | +const persister = createAsyncStoragePersister({storage}); |
| 95 | + |
| 96 | +export default function App() { |
| 97 | + return ( |
| 98 | + <PersistQueryClientProvider |
| 99 | + client={queryClient} |
| 100 | + persistOptions={{persister}} |
| 101 | + > |
| 102 | + <YourApp/> |
| 103 | + </PersistQueryClientProvider> |
| 104 | + ) |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | +!!! note "Required packages" |
| 109 | +Install `@tanstack/query-async-storage-persister` and `@tanstack/react-query-persist-client` separately. |
| 110 | + |
| 111 | +### Zustand |
| 112 | + |
| 113 | +Zustand's `persist` middleware accepts a custom storage adapter via `createJSONStorage`. Pass a factory function |
| 114 | +returning an AsyncStorage instance: |
| 115 | + |
| 116 | +```typescript |
| 117 | +import {create} from "zustand"; |
| 118 | +import {persist, createJSONStorage} from "zustand/middleware"; |
| 119 | +import {createAsyncStorage} from "@react-native-async-storage/async-storage"; |
| 120 | + |
| 121 | +const storage = createAsyncStorage("zustand"); |
| 122 | + |
| 123 | +interface BearState { |
| 124 | + bears: number; |
| 125 | + addBear: () => void; |
| 126 | + reset: () => void; |
| 127 | +} |
| 128 | + |
| 129 | +export const useBearStore = create<BearState>()( |
| 130 | + persist( |
| 131 | + (set) => ({ |
| 132 | + bears: 0, |
| 133 | + addBear: () => set((state) => ({bears: state.bears + 1})), |
| 134 | + reset: () => set({bears: 0}), |
| 135 | + }), |
| 136 | + { |
| 137 | + name: "bear-storage", |
| 138 | + storage: createJSONStorage(() => storage), |
| 139 | + } |
| 140 | + ) |
| 141 | +); |
| 142 | +``` |
| 143 | + |
| 144 | +`createJSONStorage` handles serialization, so you don't need to manually call `JSON.stringify` / `JSON.parse`. |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## Error handling |
| 149 | + |
| 150 | +### How do I handle errors from AsyncStorage? |
| 151 | + |
| 152 | +All AsyncStorage methods throw `AsyncStorageError` on failure. Use a try/catch block and inspect `e.type` to handle |
| 153 | +specific failure modes: |
| 154 | + |
| 155 | +```typescript |
| 156 | +import {AsyncStorageError, createAsyncStorage,} from "@react-native-async-storage/async-storage"; |
| 157 | + |
| 158 | +const storage = createAsyncStorage("my-app"); |
| 159 | + |
| 160 | +try { |
| 161 | + await storage.setItem("key", "value"); |
| 162 | +} catch (e) { |
| 163 | + if (e instanceof AsyncStorageError) { |
| 164 | + console.error(`Storage error [${e.type}]: ${e.message}`); |
| 165 | + } |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | +See the [Error handling](api/errors.md) guide for the full list of error types and what each one means. |
| 170 | + |
| 171 | +### What happens if a batch operation partially fails? |
| 172 | + |
| 173 | +Batch operations (`setMany`, `getMany`, `removeMany`) are atomic. If any part of the operation fails, the entire batch |
| 174 | +is rolled back and an `AsyncStorageError` is thrown. No partial writes will be committed. |
| 175 | + |
0 commit comments