【React Native+Expo】Expoでデータベース(SQLite)の使い方
スマホアプリを作る時、データを保存する必要がありますよね。
スマホではSQLiteを使う場面が多いかと思います。もちろんExpoにもSQLiteがあって、SQLiteの公式ドキュメントもあります。
が、公式ドキュメントの情報量が少ないです。
そのため、処理をまとめました。
ExpoでSQLiteを使う準備
通常通り、Expoプロジェクトを作成した上で、コマンドでexpo-sqliteをインストールします。
以下のコマンドでインストールします。
$ npx expo install expo-sqlite
ちなみに、npmでインストールされたものは、node_modules内にインストールされるので、パッと見でインストールされているのかよくわかりません。
インストールされているか確認する時は、package.jsonを確認してください。
"dependencies": {
"expo": "~47.0.8",
"expo-asset": "~8.6.2",
"expo-file-system": "~15.1.1",
"expo-sqlite": "~11.0.0",
"expo-status-bar": "~1.4.2",
"react": "18.1.0",
"react-native": "0.70.5"
},
このdependenciesにインストールされたモジュールが追加されていきます。
"expo-sqlite": "~11.0.0",
expo-sqliteが入ってて、バージョンが記載されていますね。
expo-sqliteをインポートします
ExpoでSQLiteを使うために、インストールしたexpo-sqliteをインポートします。
import * as SQLite from 'expo-sqlite';
expo-sqliteでテーブルを作る場合
今回はボタンを押したタイミングでテーブルを作成します。
<Button
title="CREATE"
onPress={() => {
const db = SQLite.openDatabase('DB.db');
db.transaction((tx) => {
// 実行したいSQL
tx.executeSql(
"CREATE TABLE IF NOT EXISTS HealthData(id integer primary key not null, height real, weight real);",
null,
() => {
// 成功時のコールバック
console.log("CREATE TABLE Success.");
},
() => {
// 失敗時のコールバック
console.log("CREATE TABLE Failed.");
return true; // return true でロールバックする
});
},
() => { console.log("Failed All."); },
() => { console.log("Success All."); }
);
}} />
// データベースを開きます。
const db = SQLite.openDatabase([DB名]);
SQLite.openDatabase([DB名]);でデータベースを開きます。
ここで指定したDB名のファイルがない場合、ファイルの作成まで行ってくれます。
トランザクションの実行
SQLite.openDatabase([DB名]);で代入した定数「db」には関数があります。
「db」に含まれる関数「transaction」を呼び出して、SQLを実行させます。
callback | SQLを実行する関数を入れます |
errorCallback | エラーが発生した時の関数を入れます |
successCallback | 成功した時の関数を入れます。 |
戻り値 | なし |
db.transactionの引数に入れるのは全て関数です。
db.transaction(
(tx) => {~~~},
() => { console.log("Failed All."); },
() => { console.log("Success All."); }
);
引数の2番目、3番目はそれぞれSQLの実行に失敗した時、成功した時の処理を入れます。
最初のcallbackに何が入るかというと、SQLを実行する関数が入ります。
sqlStatement | SQL文を入れます |
args | SQLのプリペアドステートメントの変数 |
callback | SQLが上手に動いた時に実行されるコールバック |
errorCallback | SQLを実行してエラーが発生した時のコールバック |
戻り値 | なし |
tx.executeSql(
SQL文,
null,
() => {
// 成功時のコールバック
},
() => {
// 失敗時のコールバック
return true; // return true でロールバックする
}
);
tx.executeSqlはdb.transactionの第一引数に(tx) => {~~~}を入れて、この関数の引数txを使って、executeSql関数を動かします。
処理しているSQLは以下の通りです。
CREATE TABLE IF NOT EXISTS
HealthData (
id integer primary key not null,
height real,
weight real
);
HealthDataという健康管理用のテーブルを作成しています。
IF NOT EXISTSの部分で「テーブルが無ければ作ってね」という命令をして、既にテーブルが存在しているのに改めて同名のテーブルを作ろうとする行為を防止しています。
expo-sqliteでテーブルにレコードを追加する場合
<Button
title="ADD"
onPress={() => {
const db = SQLite.openDatabase('DB.db');
db.transaction((tx) => {
// 実行したいSQL
tx.executeSql(
"INSERT INTO HealthData(id, height, weight) VALUES(?, ?, ?);",
[1, 170.0, 60.0],
() => {
// 成功時のコールバック
console.log("INSERT TABLE Success.");
},
() => {
// 失敗時のコールバック
console.log("INSERT TABLE Failed.");
return true; // return true でロールバックする
});
},
() => { console.log("Failed All."); },
() => { console.log("Success All."); }
);
}} />
使っている関数や処理の流れはテーブル作った時と同じです。
SQL文の部分が違うだけですね。
SQLはこんな感じ
INSERT INTO
HealthData(
id,
height,
weight
)
VALUES(
?, -- id
?, -- height
? -- weight
);
今回、テーブルを作った時とは違い、データを挿入するため、プリペアドステートメントを使っています。
それがSQL内の?マークの部分ですね。
この?マークの部分は次の引数のargsの値が順番に挿入されます。
このサンプルでは[1, 170.0, 60.0]の3つの値が順番に挿入され、最終的に以下のような文章として扱われます。
INSERT INTO
HealthData(
id,
height,
weight
)
VALUES(
1, -- id
170.0, -- height
60.0 -- weight
);
expo-sqliteでレコードを取得する場合
<Button
title="SHOW"
onPress={() => {
const db = SQLite.openDatabase('DB.db');
db.transaction((tx) => {
// 実行したいSQL
tx.executeSql(
"SELECT * FROM Health;",
[],
(_, resultSet) => {
// 成功時のコールバック
setItems(resultSet.rows._array);
console.log(`件数:${items.length}件`);
for (let i=0; i<items.length; i++) {
const id = items[i].id;
const height = items[i].height;
const weight = items[i].weight;
console.log(`${id}:${height}:${weight}`);
}
},
() => {
// 失敗時のコールバック
console.log("SELECT TABLE Failed.");
return false; // return true でロールバックする
});
},
() => { console.log("Failed All."); },
() => { console.log("Success All."); }
);
}} />
データを取得する際もほとんど一緒ですが、取得する場合、データを受け取らないといけないので、その部分が違います。
成功時のコールバックの引数が()から(_, resultSet)に変化しています。
SELECTで取得されたデータは「resultSet」に入ります。
resultSet.rows._arrayの中に配列の形で取得したデータが入ります。
今回はuseStateに一時的に保存しています。
expo-sqliteでデータを削除する場合
<Button
title="DELETE"
onPress={() => {
const db = SQLite.openDatabase('DB.db');
db.transaction((tx) => {
// 実行したいSQL
tx.executeSql("delete from players;",
null,
() => {
// 成功時のコールバック
console.log("DELETE TABLE Success.");
},
() => {
// 失敗時のコールバック
console.log("DELETE TABLE Failed.");
return true; // return true でロールバックする
});
},
() => { console.log("Failed All."); },
() => { console.log("Success All."); }
);
}} />
DELETEに関しては、今まで出てきた物を使ってやってます。
条件で絞り込んで削除する場合はWHEREで値はプリペアドステートメントを使いましょう。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。