React Native — Expo Firebase Kullanımı

Ayberk Cakar
5 min readJan 28, 2023

--

Herkese Selamlar 👨‍💻

Bu yazımda, Expo’yu Firebase ile birlikte nasıl kullanabiliriz konusunu basit örnekler ile anlatmaya çalışacağım. Firebase hizmetlerinden; Authentication, Storage, Firestore Database hizmelerini inceliyor olacağız. Authentication kısmında Login ve Sign Up işlemlerini, Storage kısmında Image Upload ve Firestore Database kısmında CRUD işlemlerini inceliyor olacağız.

Firebase üzerinden proje oluşturmak ve mobil projenize Firebase settings ayarlarınızı eklemek için React Native — Expo Firebase Kurulumu yazımı okuyabilirsiniz.

import * as firebase from "firebase/app";
import * as firebaseAuth from "firebase/auth";
import { getFirestore,setLogLevel } from "firebase/firestore";
import { getStorage } from "firebase/storage";

const firebaseConfig = {
apiKey: "xxxxx",
projectId: "mobileexample",
storageBucket: "mobileexample.appspot.com",
messagingSenderId: "xxxxxxxxx",
appId: "xxxxxxxxx:web:c5e8b0fed9cfd7bf10c8ef",
measurementId: "G-XXXXXXX"
};

// Initialize Firebase
const app = firebase.initializeApp(firebaseConfig);
const auth = firebaseAuth.getAuth();
const firestore = getFirestore();
const storage = getStorage();

export { auth, firestore, storage };

Settings dosyama config’imi ekliyorum. Projemde kullanacağım Authentication, Storage, Firestore Database hizmetlerini Firebase paketinden import ediyorum. Auth, firestore, storage değişkenlerimi tanımladıktan sonra, projemin içinde kullanmak için export ediyorum.

Firebase Authentication

Sign Up

import { createUserWithEmailAndPassword } from "firebase/auth";
import { setDoc, doc} from "firebase/firestore";
import { auth, firestore } from "../../firebase";

const addUserInCollection = async (user: any) => {
try {
await setDoc(doc(firestore, "users", user.uid), user);
} catch (error) {}
};

const createUser = async (registration: User) => {
await createUserWithEmailAndPassword(
auth,
registration.email,
registration.password
)
.then(async (state) => {
addUserInCollection({
name: registration.name,
uid: state.user.uid,
email: registration.email,
});
})
.catch((error) => {
if (error.code === "auth/email-already-in-use") {
alert(t("E Mail Already In Use"));
}
});
};

Yukarıda kod bloğunda yaptığım işlemleri inceleyelim;

  • İlk olarak kullanıcının girmiş olduğu e-mail ve password bilgileri ile sign-up işlemi gerçekleştiriyorum.
  • Firebase sign-up işlemini tamamladığında, Authentication içerisinde kaydımızı oluşturuyor ve bize bir uid tanımlıyor.
  • Methodun repsonse olarak bize verdiği uid ile bir users collection’ı içerisine userımı kaydedediyorum.
  • Böylelikle user’ımın bilgilerini Firestore içersinde bulunan users collection’ım ile ilişkilendirebileceğim.
  • Authentication için e-mail’i kullanıyorum ve bu işlem için gerekli olan method createUserWithEmailAndPassword.

createUserWithEmailAndPassword methoduna parametre olarak;

  • ilk olarak Firebase config’te oluşturmuş olduğum auth’u veriyorum,
  • ikinci parametre olarak e-mail’i veriyorum,
  • üçüncü parametre olarak password veriyorum.

Then-catch yapısı ile methodun sonucunu dinliyorum. Başarılı olursa kullanıcımı users collection’ına ekliyorum. Başarısız olursada catch yapısı ile error kodlarını kontrol edip alert veriyorum.

Login

import { signInWithEmailAndPassword } from "firebase/auth";
import { setDoc, doc, getDoc } from "firebase/firestore";
import { auth, firestore } from "../../firebase";

const getUser = async (userId: string) => {
const docRef = doc(firestore, "users", userId);
const docSnap = await getDoc(docRef);

if (docSnap.exists()) {
Storage.setItem('user', JSON.stringify(docSnap.data()))
}
};

const loginUser = async (login: User) => {
await signInWithEmailAndPassword(auth, login.email, login.password)
.then(async (state) => {
getUser(state.user.uid);
await navigation.dispatch(await StackActions.replace("Home"));
})
.catch((error) => {
if (error.code === 'auth/user-not-found') {
alert(t("Wrong Password"));
} else if (error.code === 'auth/wrong-password') {
alert(t("User Not Found"));
}
});
};

signInWithEmailAndPassword methoduna parametre olarak;

  • Firebase config’te oluşturmuş olduğum auth’u veriyorum,
  • ardından parametre olarak e-mail ve password bilgilerimi veriyorum.

Then-catch yapısı ile methodun sonucunu dinliyorum. Başarılı olursa kullanıcımın bilgilerini users collection’ınından getDoc yöntemi ile getiriyorum ve Local Storage’a kaydediyorum. Başarısız olursada catch yapısı ile error kodlarını kontrol edip alert veriyorum.

Firebase Firestore

Get

import { collection, getDoc } from "firebase/firestore";
import { firestore } from "../../firebase";

const getUser = async (userId: string) => {
const docRef = doc(firestore, "users", userId);
const docSnap = await getDoc(docRef);

if (docSnap.exists()) {
Storage.setItem('user', JSON.stringify(docSnap.data()))
}
};

doc methoduna parametre olarak;

  • Firebase config’te oluşturmuş olduğum firestore’u veriyorum,
  • ikinci parametre olarak hangi collection’da çalışacağımı belirtiyorum,
  • üçüncü parametre olarak getirmek istediğim user’ın id’sini veriyorum.

Ardından getDoc methoduna parametre olarak;

  • ilk methodun sonucu olan referans bilgisini veriyorum,
  • Dönen sonucu exists() ile kontrol edip, eğer bir kayıt bulduysam, onu Local Storage’a kaydediyorum.

Get All

import { collection, getDocs } from "firebase/firestore";
import { firestore } from "../../firebase";

async function getUsers() {
const usersRef = collection(firestore, "users");
const querySnapshot = await getDocs(usersRef);

querySnapshot.forEach((doc) => {
console.log("User => ", doc.data());
});
}

Get All yönteminde tüm collection’ı almak istediğim için collection methodunu kullanıyorum. collection methoduna parametre olarak;

  • Firebase config’te oluşturmuş olduğum firestore’u veriyorum,
  • ikinci parametre olarak hangi collection’ı getirmek istediğimi belirtiyorum.

Ardından getDocs methoduna parametre olarak;

  • ilk methodun sonucu olan referans bilgisimi veriyorum,
  • Oluşan sonucu forEach loop’unda dönüyorum (forEach, map, filter vb. istediğiniz loop yöntemini kullanabilirim) ve her dönüşte veriyi doc.data() ile alıyorum.

Add / Edit

import { setDoc, doc, getDoc } from "firebase/firestore";
import { firestore } from "../../firebase";

const addEditUser = async (user: any) => {
let id = toast.show(t("user.savingChanges"));
try {
const docRef = doc(firestore, "users", user.uid);
await setDoc(docRef, user)
.then(() => {
toast.update(id, t("user.changesSaved"), { type: "success" });
})
.catch(() =>
toast.update(id, t("user.changesCouldNotBeSaved"), { type: "danger" })
);
} catch (error) {}
};

doc methoduna parametre olarak;

  • Firebase config’te oluşturmuş olduğum firestore’u veriyorum,
  • ikinci parametre olarak hangi collection’da çalışacağımı belirtiyorum,
  • üçüncü parametre olarak getirmek istediğim user’ın id’sini veriyorum.

Ardından setDoc methoduna parametre olarak;

  • ilk methodun sonucu olan referans bilgisini veriyorum,
  • ikinci parametre olarak user bilgilerimi veriyorum.

Birinci method’un sonucunda herhangi bir user kaydı bulamazsa, setDoc methodunda yeni bir user kaydı oluşturuyor. Eğer bir user kaydı bulursa, verdiğim user bilgileri ile var olan kayıdı güncelliyor.

Delete

import { setDoc, doc, deleteDoc } from "firebase/firestore";
import { firestore } from "../../firebase";

const deleteUser = async (user: any) => {
const docRef = doc(firestore, "users", user.uid);
await deleteDoc(docRef);
};

doc methoduna parametre olarak;

  • Firebase config’te oluşturmuş olduğum firestore’u veriyorum,
  • ikinci parametre olarak hangi collection’da çalışacağımı belirtiyorum,
  • üçüncü parametre olarak getirmek istediğim user’ın id’sini veriyorum.

Ardından deleteDoc methoduna parametre olarak;

  • ilk methodun sonucu olan referans bilgisini veriyorum,
  • verdiğim user’a ait user kaydı varsa, silme işlemini gerçekleştiriyor.

Firebase Storage

import { storage } from "../../firebase";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import uuid from "react-native-uuid";

const uploadImage = async () => {
const blob: any = await new Promise((resolve) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.responseType = "blob";
xhr.open("GET", imageUri, true);
xhr.send(null);
});

const storageRef = ref(storage, uuid.v4() as string);
const uploadTask = uploadBytesResumable(storageRef, blob);

uploadTask.on(
"state_changed",
(snapshot) => {},
(error) => {},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
console.log('Image url --> ', downloadURL);
blob.close();
});
}
);
};

Note: İmage picker için expo-image-picker paketini kullanıyorum.

İlk olarak bir blob yaratıyorum. Blob’u yaratırken içerisine image picker’dan seçtiğim image’in uri bilgisini veriyorum.

xhr.open("GET", imageUri, true);

Ardından bir referans oluşturuyorum. Bunun için storage içerisinden gelen ref methodunu kullanıyorum ve parametre olarak;

  • Firebase config’te oluşturmuş olduğum storage’ı veriyorum,
  • ikinci parametre olarak random uuid ( react-native-uuid paketini kullanıyorum. ) oluşturup onu veriyorum.

Referansımı oluşturduktan sonra storage içerisinden gelen uploadBytesResumable methodu ile upload işlemimi başlatıyorum. Parametre olarak;

  • ref methodun sonucu olan, storageRef bilgisini veriyorum,
  • ikinci parametre olarak, oluşturduğum blob’u veriyorum.

uploadBytesResumable methodunu dinliyorum. state_changed olduğunda storage içerisinden gelen getDownloadURL methodu ile image’imin upload edilmiş olduğu url’i elde ediyorum. Son olarakta oluşturduğum blob’u close ediyorum.

Expo ile ilgili medium serimi yazmaya başlamadan önce, Starter UI Kit geliştirdim ve geliştirirken edindiğim bilgilerimi medium üzerinden aktarmaya çalışıyorum. Geliştirdiğim projeyi incelemek isterseniz, React Native Expo Starter UI Kit repomu inceleyebilirsiniz.

Yararlı olabilecek kaynaklar;

Yazımı okuduğunuz için teşekkür ederim, umarım sizin için yararlı olmuştur 🙂

İyi günler, iyi çalışmalar 🤖

--

--