RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-04-20中級

Rork アプリのデータが消える・保存されない問題の原因と解決策

Rork アプリでデータが保存されない・再起動すると消えるという問題は、原因がいくつかのパターンに絞られます。AsyncStorage の使い方から非同期処理のタイミングバグまで、実際によく起こるケースを整理して解説します。

Rork515AsyncStorage10データ保存トラブルシューティング77React Native209デバッグ22MMKV6

アプリを作ってテストしていると、「さっき入力したはずのデータが消えている」「再起動すると初期化される」という場面に出くわすことがあります。Rork で開発していると特にこのあたりで詰まりやすく、原因がコードの見た目では分かりにくいことも多いです。

今回は、Rork アプリでよく起きるデータ消失・保存失敗のパターンを整理しました。自分自身のアプリ開発でぶつかった経験も交えながら、原因の特定から修正まで説明していきます。

パターン1: AsyncStorage への書き込みが await されていない

これは非常によく見かける原因です。AsyncStorage の操作は非同期なので、await を付けずに次の処理へ進んでしまうと、保存が完了する前にアプリが次のステートに移ってしまいます。

// ❌ await なし — 保存が完了する前に次の処理が走る
const saveUserName = (name: string) => {
  AsyncStorage.setItem('userName', name);  // 保存が終わる前にreturn
  console.log('saved\!');  // この時点ではまだ保存されていない可能性がある
};
 
// ✅ 正しい書き方
const saveUserName = async (name: string) => {
  try {
    await AsyncStorage.setItem('userName', name);
    console.log('saved\!');  // ここでは確実に保存済み
  } catch (error) {
    console.error('保存エラー:', error);
  }
};

Rork の AI がコードを生成する際、AsyncStorage の await を省略してしまうことがあります。生成されたコードをそのまま使う場合は、非同期処理が正しく記述されているか確認する習慣をつけておくといいかもしれません。

パターン2: useEffect の依存配列が原因でデータが上書きされる

「保存したのに、画面を再表示すると消えている」という場合、useEffect の実行タイミングが原因になっていることがあります。

const [userName, setUserName] = useState('');
 
// ❌ 問題のあるパターン
useEffect(() => {
  // 初回だけ読み込むつもりが...
  loadUserName();
}, []); // OK
 
useEffect(() => {
  // userName が変わるたびに保存される...
  // ただし、初回レンダリング時に空文字列 '' で上書きしてしまう!
  AsyncStorage.setItem('userName', userName);
}, [userName]);  // userName の初期値 '' で保存が走る
// ✅ 修正版: isLoaded フラグで初回の空保存を防ぐ
const [userName, setUserName] = useState('');
const [isLoaded, setIsLoaded] = useState(false);
 
useEffect(() => {
  const load = async () => {
    const saved = await AsyncStorage.getItem('userName');
    if (saved \!== null) setUserName(saved);
    setIsLoaded(true);  // 読み込み完了フラグを立てる
  };
  load();
}, []);
 
useEffect(() => {
  if (\!isLoaded) return;  // 読み込み完了前は保存しない
  AsyncStorage.setItem('userName', userName);
}, [userName, isLoaded]);

isLoaded フラグを使うパターンは少し冗長に見えますが、このような問題を防ぐには確実な方法です。

パターン3: キーの衝突・タイポ

「保存はされているはずなのに読み込めない」場合、AsyncStorage のキー名を間違えている可能性があります。

// ❌ タイポでキーが一致していない
await AsyncStorage.setItem('user_name', value);      // 保存
const result = await AsyncStorage.getItem('userName'); // 読み込み(別のキー!)
console.log(result); // → null
// ✅ キーを定数で管理する
const STORAGE_KEYS = {
  USER_NAME: 'user_name',
  USER_EMAIL: 'user_email',
  APP_SETTINGS: 'app_settings',
} as const;
 
await AsyncStorage.setItem(STORAGE_KEYS.USER_NAME, value);
const result = await AsyncStorage.getItem(STORAGE_KEYS.USER_NAME); // 確実に一致

キーを文字列リテラルで直書きしていると、タイポや命名揺れが起きやすくなります。定数オブジェクトに集めておくと、オートコンプリートも効いて安全です。

パターン4: JSON のシリアライズ/デシリアライズ漏れ

AsyncStorage は文字列しか保存できません。オブジェクトや配列をそのまま渡すと [object Object] という文字列で保存されてしまい、読み込み時に正しく復元できません。

// ❌ オブジェクトをそのまま保存 → "object Object" になる
const settings = { theme: 'dark', language: 'ja' };
await AsyncStorage.setItem('settings', settings); // 型エラーになる or 文字列変換される
 
// ✅ JSON.stringify / JSON.parse を使う
await AsyncStorage.setItem('settings', JSON.stringify(settings));
 
// 読み込み時
const raw = await AsyncStorage.getItem('settings');
const settings = raw ? JSON.parse(raw) : null;
// ユーティリティ関数を作っておくと便利
const saveJSON = async (key: string, value: unknown) => {
  await AsyncStorage.setItem(key, JSON.stringify(value));
};
 
const loadJSON = async <T>(key: string): Promise<T | null> => {
  const raw = await AsyncStorage.getItem(key);
  return raw ? (JSON.parse(raw) as T) : null;
};

このユーティリティ関数を作っておくと、アプリ全体でデータの型安全性を保ちやすくなります。

パターン5: Expo Go 環境でデータが初期化される

Expo Go アプリで開発中にデータが消える場合、アプリを終了・再起動したのではなく、Expo Go の開発サーバーが再接続されたことで状態がリセットされているだけかもしれません。

実際のデータ消失かどうかは、以下の手順で確認できます。

// デバッグ用: 保存済みデータをすべてログ出力
const debugStorageKeys = async () => {
  const keys = await AsyncStorage.getAllKeys();
  console.log('保存済みキー:', keys);
  
  for (const key of keys) {
    const value = await AsyncStorage.getItem(key);
    console.log(`  ${key}:`, value);
  }
};
 
// 開発中はボタンなどからこの関数を呼べるようにしておく

Expo Go のホットリロード時は AsyncStorage の内容は保持されますが、手動でアプリを閉じて再起動した場合は読み込み処理が正しく動いているかを確認する必要があります。

パターン6: 大量データを AsyncStorage に保存しているケース

AsyncStorage はシンプルな用途には十分ですが、大量のデータ(例えば数百件のリストや画像のキャッシュ情報)を扱い始めると、書き込みが遅くなったり、まれに失敗することがあります。

この場合は MMKV や SQLite への移行を検討する価値があります。

// MMKV(mmkv パッケージ)は AsyncStorage より数十倍高速
import { MMKV } from 'react-native-mmkv';
 
const storage = new MMKV();
 
// 同期API(awaitが不要)
storage.set('userName', 'Masaki');
const name = storage.getString('userName'); // 'Masaki'
 
// オブジェクトの場合も同様にJSON変換
storage.set('settings', JSON.stringify({ theme: 'dark' }));
const raw = storage.getString('settings');
const settings = raw ? JSON.parse(raw) : null;

Rork が生成するコードでは AsyncStorage がデフォルトで使われることが多いですが、パフォーマンスが求められる場面では MMKV への切り替えを Rork の AI に指示してみてください。

詳しい使い分けについては、AsyncStorage・MMKV・SQLite の比較と選び方をご覧いただくと判断の参考になるかもしれません。

問題を素早く特定するためのデバッグ手順

  1. まず書き込みを確認する: 保存直後に getItem で読み直し、値が正しいか確認する
  2. エラーハンドリングを追加する: try/catch で例外を捕捉してログに出す
  3. キー名を確認する: getAllKeys() でどんなキーが存在するか確認する
  4. タイミングを確認する: await が抜けていないか、依存配列が正しいか見直す

これらを順番に確認するだけで、多くの場合は原因を絞り込めます。

オフラインファーストの設計で事前に防ぐ

データ消失の問題は、設計段階でオフラインを意識した構造にしておくことで大幅に減らせます。AsyncStorage + SQLite を使ったオフラインファースト設計では、より堅牢なデータ永続化のパターンを紹介しています。

まずは上記のパターン1〜3を確認してみてください。特に await の抜けとキー名のタイポは、Rork で生成したコードでも起きやすいので、コードレビューのチェック項目に加えておくといいと思います。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-05-19
Rork で AsyncStorage に大容量データを保存すると Android で CursorWindow エラーが出る原因と対処
Rork(React Native)で AsyncStorage に大きな JSON や画像メタデータを保存すると Android で発生する Row too big to fit into CursorWindow エラーの原因と、MMKV・SQLite・分割保存・圧縮など複数の現実的な対処をまとめています。
開発ツール2026-04-22
FlatList が空白で何も映らない—Rork アプリのリスト崩れを切り分ける
Rork で生成したアプリの FlatList が真っ白で何も表示されないときに、どこから疑うべきかを順番にまとめました。data・flex・keyExtractor・親要素の高さを見直すだけで直ることも多いです。
開発ツール2026-04-20
Rork 生成コードで useEffect が無限ループする原因と直し方
Rorkで生成したReact NativeコードのuseEffectが無限ループする原因を5パターン解説。依存配列の設定ミス・オブジェクト依存・setState競合など具体的なBefore/Afterコードで根本修正する方法をまとめています。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →