Firebase는 인증, 데이터베이스, 스토리지, 푸시 알림까지 BaaS(Backend as a Service)로 빠르게 백엔드를 구축할 수 있게 해줍니다.

별도의 서버 없이 앱을 만들거나 프로토타입을 빠르게 구현할 때 Firebase는 매우 유용합니다.


설치 (@react-native-firebase)

BASH
# 핵심 모듈
npm install @react-native-firebase/app

# 인증
npm install @react-native-firebase/auth

# Firestore
npm install @react-native-firebase/firestore

# Storage
npm install @react-native-firebase/storage

# iOS
cd ios && pod install

Authentication — 사용자 인증

TSX
import auth from '@react-native-firebase/auth';

// 이메일/비밀번호 회원가입
async function signUp(email: string, password: string) {
  try {
    const userCredential = await auth().createUserWithEmailAndPassword(email, password);
    console.log('가입 완료:', userCredential.user.uid);
  } catch (error: any) {
    switch (error.code) {
      case 'auth/email-already-in-use': Alert.alert('이미 사용 중인 이메일입니다'); break;
      case 'auth/weak-password': Alert.alert('비밀번호가 너무 약합니다'); break;
      case 'auth/invalid-email': Alert.alert('유효하지 않은 이메일입니다'); break;
    }
  }
}

// 로그인
async function signIn(email: string, password: string) {
  try {
    await auth().signInWithEmailAndPassword(email, password);
  } catch (error: any) {
    if (error.code === 'auth/invalid-credential') {
      Alert.alert('이메일 또는 비밀번호가 올바르지 않습니다');
    }
  }
}

// 로그아웃
async function signOut() {
  await auth().signOut();
}

// 인증 상태 감지 (실시간)
function useAuthState() {
  const [user, setUser] = useState(auth().currentUser);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = auth().onAuthStateChanged((firebaseUser) => {
      setUser(firebaseUser);
      setLoading(false);
    });
    return unsubscribe;
  }, []);

  return { user, loading };
}

Firestore — 데이터베이스

TSX
import firestore from '@react-native-firebase/firestore';

// 문서 추가
async function addPost(title: string, body: string) {
  await firestore().collection('posts').add({
    title,
    body,
    authorId: auth().currentUser?.uid,
    createdAt: firestore.FieldValue.serverTimestamp(),
    likes: 0,
  });
}

// 문서 조회 (단일)
async function getPost(postId: string) {
  const doc = await firestore().collection('posts').doc(postId).get();
  if (doc.exists) {
    return { id: doc.id, ...doc.data() };
  }
  return null;
}

// 컬렉션 조회 (목록)
async function getPosts() {
  const snapshot = await firestore()
    .collection('posts')
    .orderBy('createdAt', 'desc')
    .limit(20)
    .get();

  return snapshot.docs.map((doc) => ({
    id: doc.id,
    ...doc.data(),
  }));
}

// 실시간 구독
function useRealtimePosts() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    const unsubscribe = firestore()
      .collection('posts')
      .orderBy('createdAt', 'desc')
      .onSnapshot((snapshot) => {
        const data = snapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        setPosts(data);
      });

    return unsubscribe;
  }, []);

  return posts;
}

// 문서 수정
await firestore().collection('posts').doc(postId).update({
  title: '수정된 제목',
  updatedAt: firestore.FieldValue.serverTimestamp(),
});

// 문서 삭제
await firestore().collection('posts').doc(postId).delete();

Storage — 파일 저장

TSX
import storage from '@react-native-firebase/storage';

// 이미지 업로드
async function uploadImage(localUri: string, path: string) {
  const reference = storage().ref(path);
  await reference.putFile(localUri);
  const downloadUrl = await reference.getDownloadURL();
  return downloadUrl;
}

// 업로드 진행률 추적
function uploadWithProgress(localUri: string, path: string) {
  const reference = storage().ref(path);
  const task = reference.putFile(localUri);

  task.on('state_changed', (snapshot) => {
    const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
    console.log(`업로드: ${progress.toFixed(0)}%`);
  });

  return task.then(async () => {
    return reference.getDownloadURL();
  });
}

// 파일 삭제
await storage().ref('images/photo.jpg').delete();

실전: 프로필 이미지 + Firestore 연동

TSX
async function updateProfilePhoto(userId: string, imageUri: string) {
  // 1. Storage에 이미지 업로드
  const path = `profiles/${userId}/avatar.jpg`;
  const downloadUrl = await uploadImage(imageUri, path);

  // 2. Firestore 프로필 문서 업데이트
  await firestore().collection('users').doc(userId).update({
    photoUrl: downloadUrl,
    updatedAt: firestore.FieldValue.serverTimestamp(),
  });

  // 3. Auth 프로필 업데이트
  await auth().currentUser?.updateProfile({
    photoURL: downloadUrl,
  });

  return downloadUrl;
}

보안 규칙

PLAINTEXT
// Firestore 보안 규칙 (Firebase Console에서 설정)
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 인증된 사용자만 읽기/쓰기
    match /posts/{postId} {
      allow read: if true;
      allow create: if request.auth != null;
      allow update, delete: if request.auth.uid == resource.data.authorId;
    }

    // 본인 프로필만 수정
    match /users/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

정리

  • Firebase는 인증, 데이터베이스, 스토리지 를 통합적으로 제공합니다
  • onAuthStateChanged인증 상태를 실시간 감지할 수 있습니다
  • Firestore의 onSnapshot으로 ** 실시간 데이터 동기화 **가 가능합니다
  • ** 보안 규칙 **을 반드시 설정하세요 — 기본 설정은 모든 접근을 허용합니다
  • 프로덕션에서는 비용 관리를 위해 ** 쿼리 최적화와 인덱싱 **에 신경 써야 합니다
댓글 로딩 중...