ReactNative(Expo)でfirebase/firestoreと接続し情報を登録/取得する。【2023年】
「React Native でfirebase接続したいけど、何故かエラーが出てうまくいかない」
「firebaseの仕様が変更されて、どう実装したらいいかを知りたい」
今回は、ReactNative(Expo)を使って、firebaseに接続し情報を登録、リアルタイムで取得する方法について解説いたします。
この記事から、どのように実装していけばいいのかのヒントを得られることができると思いますので、ぜひ参考にしてみてください。
目次(クリックで読みたい部分にジャンプできます)
firebaseのセットアップ
まずは、firebaseのデータベースを作成していきます。簡単に説明は書いていますが、わかりづらかったら他のサイトを参考にしてみてください。
データベースの作成
firebaseに会員登録して、新たなプロジェクトを作成してください。(ここまでは画面に従ってできるはずです。)
あとは、以下のように、</> このマークのwebを選択します。
ニックネームを追加したら、②firebase SDKの追加が出てきます。
npmを使用するを選択し、npm install firebase を実行しましょう。
また、その後に記載してある文はfirebaseconfig.jsというファイルを作ってそこに保存しておくことをお勧めします。(Expoの公式ドキュメントにはそのように記載してある)
私がfirebaseに接続するときの、firebaseconfig.jsの中身はこのように記載しています。
そして、呼び出す必要がある画面などに、以下のようにインポートしています。
fireStoreを利用するときは、このインポートしたappが必要になります。
firestoreのデータ構造
今回、私が実装するfirestoreとの接続ですが、実際のfirestoreの構造を把握しておいた方が理解しやすいかと思いますので、まずは、今回の実装で使うfirestoreのデータ構造を説明します。
全体の構造は、次のようになっています。
ホーム>user>(userID)>memos>(ドキュメントID)>ドキュメント
①usersからmemosまで
②memosからドキュメントまで
ちなみに、memosの後にある、ドキュメントIDですが、これはデータを登録した際にfirestoreが自動的に割り振ってくれるものです。なので、私たちは、memosの中にデータを格納することを指示するだけで良いです。
では、実際にfirestoreに接続して、データをやり取りしていきましょう!
データの追加
データをfirestoreに追加する
import React, { useState } from "react";
import { StyleSheet, Text, View, TextInput, KeyboardAvoidingView, } from 'react-native';
import CircleButton from "../components/CircleButton";
import { getFirestore } from "firebase/firestore";
import { collection, addDoc } from "firebase/firestore";
import { app } from "../../firebaseconfig";
import { getAuth } from "firebase/auth";
export default function MemoCreateScreen(){
const [ bodyText, setBodyText ] = useState('');
const db = getFirestore(app);
const auth = getAuth();
const currentUser = auth.currentUser;
//ボタンが押されたとき(onPress)に動く関数
function handlePress() {
try {
const docRef = addDoc(collection(db, `users/${currentUser.uid}/memos`), {
bodyText,
updateAt: new Date(),
});
console.log("Document written with ID: ", docRef);
}
catch (e) {
console.error("Error adding document: ", e);
}
}
//流れ①:return以下が読み込まれる。
return (
<KeyboardAvoidingView style={styles.container} behavior="height">
<View style={styles.inputContainer}>
<TextInput
value={bodyText}
multiline
style={styles.input}
//流れ②:以下のonChangeTextでTextinputの中に入力されたtextが変更されると、setBodyTextが実行されて、bodyTextにtextがインプットされる
onChangeText={(text) => { setBodyText(text); }}
autoFocus
/>
</View>
<CircleButton
style={{ bottom: 40 }}
name="check"
//流れ③:ボタンを押すと、handlePress関数が実行される。
onPress={handlePress}
></CircleButton>
</KeyboardAvoidingView>
)
}
//以下スタイルシートなので、気にしなくて良い。
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
inputContainer: {
paddingHorizontal: 24,
paddingVertical: 32,
flex: 1,
},
input: {
flex: 1,
textAlignVertical:'top',
fontSize: 16,
lineHeight: 24,
}
})
処理の全体の流れとしては、コードの中に記載した、流れ①〜③のように動きます。
流れ②で記載している
onChangeText={(text) => { setBodyText(text); }}
は、useStateの構文を使っています。setBodyTextという関数で、textをBodyTextに当てはめるようにしています。(少し複雑でもあるので、別記事で紹介しようと思います。)
関数handlePressの中身について
データを追加するときは、addDoc関数を用います。
const docRef = addDoc(collection(db, `users/${currentUser.uid}/memos`), {
bodyText,
updateAt: new Date(),
});
公式サイトで、dbとなっているところは、全て
const db = getFirestore(app);
と置き換えてしまって大丈夫です。
データの格納場所は、memosまでを指定しましょう。先ほども少し話しましたが、ドキュメントIDは勝手に追加され、その中に自分が追加したいデータが格納されます。
データの読み込み
1回だけデータを取ってくる(呼び出された時のみ)
import { collection, getDocs, getFirestore } from "firebase/firestore";
import { query, orderBy } from "firebase/firestore";
const db = getFirestore(app);
const auth = getAuth();
const currentUser = auth.currentUser;
q = query(collection(db, `users/${currentUser.uid}/memos`), orderBy("updateAt", "asc"));
const querySnapshot = await getDocs();
querySnapshot.forEach((doc) => {
//好きな処理を書いてください。
console.log(`${doc.id} => ${doc.data()}`);
});
一回だけデータを取ってきたい場合などはgetDocsを使うと良いでしょう。
今回、並び替えなども記述しています。
q = query(collection(db, `users/${currentUser.uid}/memos`), orderBy("updateAt", "asc"));
whereメソッドなども入れることが可能です。不要であれば、消しておいてください。不要の場合は、以下のようにします。
q = collection(db, `users/${currentUser.uid}/memos`);
データをリアルタイムで監視する
const db = getFirestore(app);
const auth = getAuth();
const currentUser = auth.currentUser;
const [memos, setMemos] = useState([]);
const q = query(collection(db, `users/${currentUser.uid}/memos`), orderBy("updateAt", "asc"));
//降順、昇順、desc asc
const unsubscribe = onSnapshot(q, (querySnapshot) => {
let userMemos = [];
querySnapshot.forEach((doc) => {
const data = doc.data();
userMemos.push({
id: doc.id,
bodyText: data.bodyText,
updateAt: data.updateAt.toDate(),
});
});
setMemos(userMemos);
});
onSnapshot関数は、画面表示した時に呼び出す&firestore内のデータが更新されたときに、自動で実行されます。
例えば、関数の中に、onSnapshot関数があったとしても、onSnapshot関数の中の処理のみが実行されます。
以下のコードで、useStateを使って、userMemosの内容をmemosに代入しています。
setMemos(userMemos);
そうすることで、画面内にmemosが表示される仕様しておけば、同時に反映されるようになります。
アプリなどで、一覧表示しているときなどに、DBを反映するだけで、アプリが動くので便利に使えますね。
まとめ
今回は、ReactNative(Expo)を使って、firebaseのfirestoreと接続してみました。
今回の実装では、firestoreの他にもユーザーのログインを監視するAuthenticationを使っていました。
以下の記事では、ExpoにAuthenticationを導入する方法なども紹介しているので、参考にしてみてください。