끄적이는 개발노트

React Native - Firebase (Realtime Database & Firestore) 본문

React Native

React Native - Firebase (Realtime Database & Firestore)

크런키스틱 2025. 3. 25. 21:40
728x90

이전 글에서 SQLite의 선택과정을 가볍게 설명하면서 Firebase 데이터베이스를 언급했었다. 이는 분명 트래픽이 적고 데이터 타입이 복잡하지 않다면 굉장히 탁월한 선택이다. 본인 역시 사용을 했었고 여전히 어플에 Authentication 기능과 함께 데이터 저장이 필요하다면 1순위로 떠올리는 것이 Firebase이다.

 

그 중 Cloud Storage는 말 그대로 저장소 storage로 이미지, 동영상과 같은 컨텐츠를 저장하는데 활용된다. DB로 사용되는 것은 크게 Realtime Database 와 Firestore가 있는데 이 둘의 특징은 다음과 같다.

 

  • 공통점
    1. NoSQL 데이터베이스
    2. 쿼리 사용 (정렬 및 필터링)
  • 차이점
    • Realtime Database
      • 데이터를 하나의 JSON 형태로 저장
      • 하나의 쿼리에 정렬 및 필터링 하나만 가능
      • 결과값을 전체 제공 (하위 값도 return)
      • 데이터 평면화가 요구됨 (하위 값도 전부 반환하기 때문에)
    • Cloud Firestore
      • 문서 컬렉션으로 저장
      • 복합 쿼리 가능
      • 결과에 해당하는 값만 반환

따라서, Realtime Database와 Cloud Firestore 중 선택할 때 고려해야 할 점은 아래와 같이 정리할 수 있다.

  • Realtime Database
    • 적은 양의 데이터가 자주 변경
    • 데이터의 형태가 간단한 JSON 트리
    • 기본적인 데이터 동기화 기능
  • Cloud Firestore
    • 고급 쿼리 기능 필요
    • 대용량 데이터가 자주 읽힘
    • 구조화된 컬렉션
    • 단일 데이터베이스

 

본인의 경우 Realtime Database와 Cloud Firestore를 둘 다 사용했었다. 지도와 관련하여 제작한 어플에서 간단한 JSON 구조와 함께 데이터의 호출이 잦고 변경이 자주 이루어지는 기본 지역 매핑 데이터는 Realtime Database에 저장했고, 지역에 따라 구분되어 각각 CRUD가 이루어지는 데이터를 Cloud Firestore에 저장했었다.

 

물론 요금 역시도 고려했었는데 아래 공식 사이트를 확인하는 것이 깔끔하다.

https://firebase.google.com/pricing?hl=ko

 

Firebase Pricing

무료로 Firebase를 시작하고 전 세계 수백만 명의 사용자로 확장하세요. 무료 할당량 소진 후 사용한 만큼만 비용을 지불하면 됩니다.

firebase.google.com

 

 

● Realtime Database

1. Firebase 설정

 

rule은 이후에도 변경이 가능하기 때문에 일단은 테스트용으로 .read와 .write를 true로 편하게 설정하면 된다.

 

이 후, 실제 production 용으로는 아래와 같이 rule을 로그인 정보와 매칭시키는 등 설정해주면 된다.

{
   "rules": {
     "users": {
       "$uid": {
         ".read": "$uid === auth.uid",
         ".write": "$uid === auth.uid"
       }
     }
   }
 }

 

 

2. 설치

npm install @react-native-firebase/database
#or
yarn add @react-native-firebase/database

 

 

3. 코드

기본적인 CRUD용 예시 코드로 아래와 같다.

여기서 설정한 .env의 FirebaseDatabase는 아래 사진의 가린 부분의 주소를 설정한 값이다.

(기본 'us-central1' 이 아닌 경우 database URL 설정 작업이 필요하기 때문)

// realtime.ts

import {firebase} from '@react-native-firebase/database';
import {FirebaseDatabase} from '@env';

const reference = firebase.app().database(FirebaseDatabase);

interface TestData {
  uid: string;
  title: string;
  contents: string;
}

export const setRealtime = async (data: TestData) => {
  console.log('데이터 생성');
  return await reference.ref(`/users/${data.uid}`).set(data);
};

export const updateRealtime = async (data: TestData) => {
  console.log('데이터 업데이트');
  return await reference.ref(`/users/${data.uid}`).update(data);
};

export const readRealtime = async (uid: string) => {
  console.log('데이터 읽기');
  return await reference.ref(`/users/${uid}`).once('value');
};

export const deleteRealtime = async (uid: string) => {
  console.log('데이터 삭제');
  return await reference.ref(`/users/${uid}`).remove();
};
// test2.tsx

import {Test2Props} from '@/types/stack';
import {readRealtime, setRealtime} from '@/utils/realtime';
import {Button, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';

const Test2Screen = ({navigation}: Test2Props) => {
  const testData = {
    uid: '1',
    title: 'title',
    contents: 'test',
  };

  return (
    <SafeAreaView className="flex-1">
      <View className="w-full h-full flex justify-center items-center bg-white">
        <Button title="저장" onPress={() => setRealtime(testData)} />
        <Button title="읽기" onPress={() => readRealtime(testData.uid)} />
      </View>
    </SafeAreaView>
  );
};

export default Test2Screen;

 

 

4. 실행결과

데이터의 CRUD가 잘 이루어지는 것을 볼 수 있다.

 

 

● Firestore Database

1. Firebase 설정

 

마찬가지로 rule은 이후에 설정해주면 된다.

 

이 후, 실제 production 용으로는 아래와 같이 rule을 인증이 된 사용자(로그인이 된 사용자)면 통과하게끔 혹은 본인의 입맛에 맞게끔 설정하면 된다.

allow read, write: if request.auth != null;

 

 

2. 설치

npm install @react-native-firebase/firestore
#or
yarn add @react-native-firebase/firestore

 

 

3. 코드

기본적인 CRUD용 예시 코드는 아래와 같다.

기존의 사용방법과는 달라졌는데 공식문서를 통해 확인가능하다.

https://rnfirebase.io/migrating-to-v22

 

Migrating to v22 | React Native Firebase

Copyright © 2017-2020 Invertase Limited. Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. Some partial documentation, under the

rnfirebase.io

 

// firestore.ts

import {
  getFirestore,
  doc,
  setDoc,
  getDoc,
  deleteDoc,
} from '@react-native-firebase/firestore';

const db = getFirestore();

interface TestData {
  uid: string;
  title: string;
  contents: string;
}

export const createDocument = async (data: TestData) => {
  console.log('파이어스토어 생성', data);
  const userDoc = doc(db, 'users', data.uid);
  await setDoc(userDoc, data);
};

export const readDocument = async (uid: string) => {
  console.log('파이어스토어 읽기');
  const userDoc = doc(db, 'users', uid);
  const result = await getDoc(userDoc);
  return result.data();
};

export const deleteDocument = async (uid: string) => {
  console.log('파이어스토어 삭제');
  const userDoc = doc(db, 'users', uid);
  await deleteDoc(userDoc);
};
// test2.tsx

import {Test2Props} from '@/types/stack';
import {createDocument, deleteDocument, readDocument} from '@/utils/firestore';
import {Button, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';

const Test2Screen = ({navigation}: Test2Props) => {
  const testData = {
    uid: '1',
    title: 'title',
    contents: 'test',
  };

  return (
    <SafeAreaView className="flex-1">
      <View className="w-full h-full flex justify-center items-center bg-white">
        <Button title="저장" onPress={() => createDocument(testData)} />
        <Button title="읽기" onPress={() => readDocument(testData.uid)} />
        <Button title="삭제" onPress={() => deleteDocument(testData.uid)} />
      </View>
    </SafeAreaView>
  );
};

export default Test2Screen;

 

 

4. 실행결과

데이터의 CRUD가 잘 이루어지는 것을 볼 수 있다.

728x90