はじめに
React Native + Expo + TypeScript な環境で SQLite のデータベースにアクセスする方法を試してみたのですが、なかなかうまくいかず苦労したので、その方法を掲載します。
そもそもとして、ローカルのデータベースには Realm (レルム)を使用したかったのですが、Expo は Realm をサポートしていないので泣く泣くサポートされている SQLite を使用することにしました。
準備
以下のコマンドをプロジェクトのルートディレクトリで実行して、Expo のライブラリをインストールします。
$ expo install expo-sqlite $ expo install expo-file-system
実装サンプル
SQLite を実行するサンプルを以下に掲載します。
既存のソースから抜粋しているので、動作するとは思いますがその前提で参照してください。
import React, { useState } from 'react'; import * as SQLite from 'expo-sqlite'; import * as FileSystem from 'expo-file-system'; const SQLiteSample: React.FunctionComponent = () => { const [items, setItems] = useState<SQLite.SQLResultSet>(); const initializeDatabase = () => { // DBの作成先を出力 console.log(FileSystem.documentDirectory + 'SQLite/'); // DBのオープン const db = SQLite.openDatabase('DB.db'); db.transaction( tx => { tx.executeSql( 'create table if not exists players (id integer primary key not null, name text);', // 実行したいSQL文 null, () => { console.log('success'); }, // 成功時のコールバック関数 () => { console.log('fail'); return true; // ロールバックする場合はtrueを返す }, // 失敗時のコールバック関数 ); tx.executeSql( 'insert into players (id, name) values (?, ?),(?, ?);', [1, 'yamada', 2, 'sato'], () => { console.log('success'); }, // 成功時のコールバック関数 () => { console.log('fail'); return true; // ロールバックする場合はtrueを返す }, // 失敗時のコールバック関数 ); tx.executeSql( 'select * from players where id = ?;', [2], (_, resultSet) => { // SUCCESS setItems(resultSet); }, () => { console.log('fail'); return false; // 何もしない }, // 失敗時のコールバック関数 ); }, () => { console.log('fail all'); }, // 失敗時のコールバック関数 () => { console.log('success'); }, // 成功時のコールバック関数 ); }; const showData = () => { for (let i = 0; i < items.rows.length; i++) { const id = items.rows.item(i).id; const name = items.rows.item(i).name; console.log(`${id}:${name}`); } }; const deleteData = () => { const db = SQLite.openDatabase('DB.db'); db.transaction( tx => { tx.executeSql( 'delete from players;', null, () => { console.log('success'); }, // 成功時のコールバック関数 () => { console.log('fail'); return true; // ロールバックする場合はtrueを返す }, // 失敗時のコールバック関数 ); }, () => { console.log('fail'); }, // 失敗時のコールバック関数 () => { console.log('success'); }, // 成功時のコールバック関数 ); }; return ( <> <Button onPress={() => initializeDatabase()}> <Text>Initialize database</Text> </Button> <Button onPress={() => showData()}> <Text>Show data</Text> </Button> <Button onPress={() => deleteData()}> <Text>Delete data</Text> </Button> </> ); };
SQLite は executeSql
ですべての処理を行います。
データベースの作成場所は、アプリケーションのデフォルト保存領域に保存されます。
console.log(FileSystem.documentDirectory + 'SQLite/');
でデータベースの作成場所を出力しています。
あとは基本的にコメントを付けてある通りなのですが、1点注意事項があり、select
文のあとのsetItems
の直後にitems
を操作する処理を書いても、データが未設定のためデータがゼロ件になり処理が失敗します。
上記サンプルでは、ボタンを分けているのでタイミングの問題は起きないですが、select
文のあとにitems
を扱いたい場合は、useEffect
を使用する必要があります。イメージとしては以下のような感じですね。
useEffect(() => { // items を扱う処理 }, [items])
items
の値が変わったら、items
を扱う処理が実行されます。
おわりに
ざっくり、React Native + Expo + TypeScript で SQLite のデータベースにアクセスする方法をご紹介しました。
複数データやパラメータクエリのサンプルも掲載しているので、基本的なことはこれでできると思います。
ハマりどころが多いですが、いろいろ試してみてください。