PR
SQLite CRUDSQL QUERY

【ReactNative】SQLiteでデータを処理する方法〜アプリ実装済み〜

dentaku-tablet SQLite
スポンサーリンク

この記事は 2024 年当時の記録です(2026 年 7 月 追記)

本文の expo-sqlite のコードは古い API で書かれており、そのままでは動きません。expo-sqlite はその後、内部から書き直され、コールバックを使う db.transaction() / tx.executeSql() 方式は廃止されました。現在は async / await ベースの API になっています。SQL 文(CREATE / INSERT / SELECT / UPDATE / DELETE)自体は同じなので、呼び出し方を新しい形に置き換えれば、本文の考え方はそのまま使えます。

新しい API の対応表

  • SQLite.openDatabase("foo.db")await SQLite.openDatabaseAsync("foo.db")
  • db.transaction((tx) => {...}) → 廃止。各操作を直接 await で呼ぶ
  • 書き込み(INSERT / UPDATE / DELETE)→ await db.runAsync(...)
  • 複数行の取得(SELECT)→ await db.getAllAsync(...)
  • 1 行だけ取得 → await db.getFirstAsync(...)
  • まとめて実行 → await db.execAsync(...)

本文の addItem を新しい書き方にすると、次のようになります。

import * as SQLite from "expo-sqlite";

// データベースを開く(一度だけ)
const db = await SQLite.openDatabaseAsync("foo.db");

// テーブル作成
await db.execAsync(
  "CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY NOT NULL, done INT, value TEXT);"
);

// 追加(INSERT)
const addItem = async (text) => {
  if (!text) return false;
  await db.runAsync("INSERT INTO items (done, value) VALUES (0, ?)", text);
  const rows = await db.getAllAsync("SELECT * FROM items");
  console.log(rows);
};

// 更新(UPDATE)
const updateItem = async (id) => {
  await db.runAsync("UPDATE items SET done = 1 WHERE id = ?", id);
};

// 削除(DELETE)
const deleteItem = async (id) => {
  await db.runAsync("DELETE FROM items WHERE id = ?", id);
};

本文の useForceUpdate() で強制的に再描画する手法も不要になりました。async / await で取得した結果を useState にそのまま入れれば画面が更新されます。また、SQLiteProvideruseSQLiteContext() を使うと、コンポーネント間でデータベースを共有しやすくなります。詳しくは expo-sqlite 公式ドキュメントをご確認ください。

※ 上記は公式ドキュメントに基づく整理であり、新しい環境での再検証は行っていません。実際に実装される際は公式ドキュメントをご確認ください。

expo-sqlite を使用すると、WebSQL のような API を通じてクエリできるデータベースにアプリがアクセスできるようになります。 データベースはアプリを再起動しても保持されます。

開発環境(Expo Bare)

  • “typescript”: “^5.2.2”
  • “expo”: “~49.0.13”,
  • “react”: “18.2.0”,
  • “react-native”: “0.72.6”,
  • “expo-router”: “^2.0.0”,
  • “react-native-paper”: “^5.10.6”,
  • expo-sqlite: “~11.3.3”,

セットアップする

.db 拡張子を認識させる

// metro.config.js

const { getDefaultConfig } = require('expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

defaultConfig.resolver.assetExts.push('db'); // <-- 追加する

module.exports = defaultConfig;

expo-sqlite

パッケージを設置する

npx expo install expo-sqlite
npx pod-install

フック(Hooks)を作成する

SQLiteの使用上、SQL Queryを実行する際、コンポネートのレンダリング(re-render)を手動で行う必要がありますので、useForceUpdateフックを作成しておきます。

export function useForceUpdate() {
  const [value, setValue] = React.useState(0);
  return () => setValue(value + 1);
}

データを処理する(CRUD+)

データベースをオープンする

import * as SQLite from "expo-sqlite";

function openDatabase() {
  const db = SQLite.openDatabase("foo.db"); // データベース名(foo.db)は任意
  return db;
}

const db = openDatabase()

export default function RootLayout() {
...

CREATE TABLE …

  useEffect(() => {
    db.transaction((tx) => {
      tx.executeSql(
        "CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT, done INT, value TEXT);"
      );
    });
  }, []);

INSERT INTO …

SELECT <カラム名> FROM …

  const forceUpdate = useForceUpdate();

  const addItem = (text) => {
    if (text === null || text === "") {
      return false;
    }

    db.transaction(
      (tx) => {
        tx.executeSql("INSERT INTO items (done, value) values (0, ?)", [text]);
        tx.executeSql("SELECT * FROM items", [], (_, { rows }) =>
          console.log(JSON.stringify(rows))
        );
      },
      undefined,
      forceUpdate
    );
  };

UPDATE <テーブル名> SET …

  const forceUpdate = useForceUpdate();

  const updateItem = (id) => {
    db.transaction(
      (tx) => {
        tx.executeSql("UPDATE items SET done = 1 WHERE id = ?;", [id]);
      },
      undefined,
      forceUpdate
    );
  };

DELETE FROM …

  const forceUpdate = useForceUpdate();

  const deleteItem = (id) => {
    db.transaction(
      (tx) => {
        tx.executeSql("DELETE FROM items WHERE id = ?;", [id]);
      },
      undefined,
      forceUpdate
    );
  };

DROP TABLE …

  const forceUpdate = useForceUpdate();

  const dropTable = (id) => {
    db.transaction(
      (tx) => {
        tx.executeSql("DROP TABLE IF EXISTS items ");
      },
      undefined,
      forceUpdate
    );
  };

リリースする

※上記の詳細は以下のアプリに実装されています!

この SQLite の実装は、以下のアプリで使っています。実際の動作は各ストアからご確認いただけます。

Kotango(ハングル単語)

hajimari(自分だけのはじまりを記録する)

コメント

タイトルとURLをコピーしました