Expo SQLiteとDrizzle ORMで始めるReact Nativeのローカルデータベース開発
🎯 はじめに
React Nativeアプリで本格的なローカルデータベースを構築していきたい!
ということで、Drizzle公式ドキュメントに基づいて、Expo SQLiteとDrizzle ORMを組み合わせてデータベースを導入してみました。
📖 本文
Step 1: Expoプロジェクトの用意
Expoのプロジェクトを用意、もしくは新しく作成しておきます。
Expoのセットアップについては別記事で書きました。
Step 2: Expo SQLiteパッケージのインストール
# 必要なパッケージのインストール
pnpm expo install expo-sqlite
Step 3: 必要なパッケージのインストール
# drizzle-ormとdrizzle-kitをインストール
pnpm add drizzle-orm
pnpm add -D drizzle-kit babel-plugin-inline-import
Step 4: データベース接続の設定
App.tsxや_layout.tsxなどのアプリのエントリーポイントでデータベース接続を初期化します。
import * as SQLite from 'expo-sqlite';
import { drizzle } from 'drizzle-orm/expo-sqlite';
const expo = SQLite.openDatabaseSync('db.db');
const db = drizzle(expo);
Step 5: テーブルスキーマの作成
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const usersTable = sqliteTable("users_table", {
id: int().primaryKey({ autoIncrement: true }),
name: text().notNull(),
age: int().notNull(),
email: text().notNull().unique(),
});
Step 6: Drizzle設定ファイルの作成
Drizzle configは、Drizzle Kitで使用される設定ファイルで、データベース接続、マイグレーションフォルダ、スキーマファイルに関するすべての情報が含まれています。
./src/db/schema.ts: スキーマ定義はソースコードなのでsrc/に配置
./drizzle: 自動生成されるマイグレーションファイルなので、ルートに配置
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "sqlite",
driver: "expo",
schema: "./src/db/schema.ts",
out: "./drizzle",
});
Step 7: Metro設定の更新
SQLファイルの読み込みを可能にするため、Metro設定を更新します。
const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push('sql');
module.exports = config;
Step 8: Babel設定の更新
マイグレーションファイル(.sqlファイル)をインポートするために、Babel設定の更新を行います。
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [["inline-import", { "extensions": [".sql"] }]]
};
};
Step 9: マイグレーションの生成
スキーマからマイグレーションファイルを生成します。
npx drizzle-kit generate
これによって、Step 6で設定していた./drizzleフォルダにマイグレーションファイルが生成されます。
Step10: アプリの起動と動作確認
データベース操作用のコンポーネント例:
import { Text, View } from 'react-native';
import { useEffect, useState } from 'react';
import { usersTable } from './db/schema';
import { db } from './src/provider/DrizzleProvider';
export default function MainApp() {
const [items, setItems] = useState<typeof usersTable.$inferSelect[]>([]);
useEffect(() => {
(async () => {
// サンプルデータの挿入
await db.delete(usersTable);
await db.insert(usersTable).values([
{
name: 'John',
age: 30,
email: 'john@example.com',
},
]);
// データの取得
const users = await db.select().from(usersTable);
setItems(users);
})();
}, []);
return (
<View
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
height: '100%',
justifyContent: 'center',
}}
>
{items.map((item) => (
<Text key={item.id}>{item.email}</Text>
))}
</View>
);
}
(お好みで)プロバイダーパターンでの実装
これは好みですが、筆者はApp.tsxや_layout.tsxなどのエントリーポイントに色々と書くと、関連しているものが分かりにくくなって辛いため、関心の分離として、データベース関連の処理をプロバイダーに用意しています。
まず、データベースプロバイダーを作成します:
import { drizzle } from "drizzle-orm/expo-sqlite";
import { useMigrations } from "drizzle-orm/expo-sqlite/migrator";
import { openDatabaseSync } from "expo-sqlite";
import type { ReactNode } from "react";
import migrations from "../../drizzle/migrations";
const expoDb = openDatabaseSync("db.db");
export const db = drizzle(expoDb);
interface DrizzleProviderProps {
children: ReactNode;
}
export function DrizzleProvider({ children }: DrizzleProviderProps) {
const { success, error: migrateError } = useMigrations(db, migrations);
// マイグレーションエラーの処理
if (migrateError) {
console.error("Migration Error:", migrateError);
throw migrateError;
}
// マイグレーション完了まで待機
if (!success) {
return null; // ローディング表示を検討
}
return <>{children}</>;
}
次に、App.tsxでプロバイダーを使用します:
import { DrizzleProvider } from "./src/provider/DrizzleProvider";
import MainApp from "./MainApp";
export default function App() {
return (
<DrizzleProvider>
<MainApp />
</DrizzleProvider>
);
}
Drizzle Studioでのデバッグ環境構築
Drizzle Studioを利用することでブラウザ上からデータベースの内容を確認することができます。
GUIを利用してデータベースを確認できる非常に便利なツールです。
Drizzle StudioをReact Nativeで利用するため追加のライブラリをインストールします:
pnpm add expo-drizzle-studio-plugin
DrizzleProvider.tsxにDrizzle Studioの設定を追加します:
import { drizzle } from "drizzle-orm/expo-sqlite";
import { useMigrations } from "drizzle-orm/expo-sqlite/migrator";
+ import { useDrizzleStudio } from "expo-drizzle-studio-plugin";
import { openDatabaseSync } from "expo-sqlite";
import type { ReactNode } from "react";
import migrations from "@/drizzle/migrations";
const expoDb = openDatabaseSync("db.db");
export const db = drizzle(expoDb);
interface DrizzleProviderProps {
children: ReactNode;
}
export function DrizzleProvider({ children }: DrizzleProviderProps) {
const { success, error: migrateError } = useMigrations(db, migrations);
+ // Drizzle Studio の設定(開発環境でのみ有効)
+ useDrizzleStudio(expoDb);
// マイグレーションエラーの処理
if (migrateError) {
console.error("Migration Error:", migrateError);
throw migrateError;
}
// マイグレーション完了まで待機
if (!success) {
return null; // ローディング表示を検討
}
return <>{children}</>;
}
Drizzle Studioの起動手順:
-
npx expo startコマンドを実行してExpo Goを起動 -
ターミナル画面で
Shift + mを押してメニューを表示 -
"Open expo-drizzle-studio-plugin"を選択
? Dev tools (native only) › - Use arrow-keys. Return to submit.
Inspect elements
Toggle performance monitor
Toggle developer menu
Reload app
Open React devtools
❯ Open expo-drizzle-studio-plugin
- ブラウザが自動で起動し、データベースの中身がGUIで表示されます
主な機能:
- テーブル構造の可視化: スキーマとリレーションを図で確認
- データの参照・編集: GUIでのCRUD操作
- リアルタイム更新: アプリでの変更がリアルタイムで反映
📋 まとめ
Expo SQLiteとDrizzle ORMの組み合わせにより、React Nativeアプリにローカルデータベース環境を構築できました。
Discussion