Гид по технологиям

React и Firebase: CRUD с Firestore

5 min read Frontend Обновлено 05 Jan 2026
React + Firebase: CRUD с Firestore
React + Firebase: CRUD с Firestore

Фрагменты кода в текстовом редакторе

React в сочетании с Firebase позволяет быстро создавать отзывчивые приложения с минимальным бэкендом. Если вы уже знакомы с React, интеграция Firestore — естественный следующий шаг. Здесь мы подробно пройдём весь путь: от настройки проекта до полного CRUD-примера и рекомендаций по надёжности и безопасности.

Что вы узнаете

  • Как подключить React-приложение к Firebase Firestore
  • Как записывать, читать, обновлять и удалять документы
  • Когда использовать addDoc vs setDoc
  • Практические рекомендации, чеклисты и распространённые ошибки

Важно: определения в одну строку

  • Firestore — облачная NoSQL база данных от Firebase, оптимизированная для реального времени.
  • addDoc — добавляет документ в коллекцию с автоматически сгенерированным ID.
  • setDoc — записывает или перезаписывает документ по заданному ID, можно использовать merge для частичных изменений.

Подключение React к Firebase Firestore

Если вы ещё не создали проект в Firebase, зайдите в консоль Firebase и создайте новый проект, подключите Firestore. Процесс простой, особенно если React-приложение уже создано.

Создайте папку firebase_setup внутри src и файл firebase.js. Вставьте конфигурацию, которую выдаёт консоль Firebase:

import { initializeApp } from "firebase/app";  
import {getFirestore} from "@firebase/firestore"  
  
const firebaseConfig = {  
  apiKey: process.env.REACT_APP_apiKey,  
  authDomain: process.env.REACT_APP_authDomain,  
  projectId: process.env.REACT_APP_projectId,  
  storageBucket: process.env.REACT_APP_storageBucket,  
  messagingSenderId: process.env.REACT_APP_messagingSenderId,  
  appId: process.env.REACT_APP_appId,  
  measurementId: process.env.REACT_APP_measurementId  
};  
  
const app = initializeApp(firebaseConfig);  
export const firestore = getFirestore(app)  

Переменная firestore содержит окружение Firestore — используйте её везде, где делаете запросы к базе.

Примечание о секретах: код использует .env для маскировки конфигурации. Для production рассмотрите использование защищённого хранилища секретов (CI/CD secret store, Vault, секреты хоста) и ограничение прав ключей.

Установите библиотеки firebase и uuid:

npm install firebase uuid  

uuid опционален — можно использовать его как дополнительное уникальное поле внутри документа.

Демонстрация: что мы строим

Ниже — полный пример DOM и состояний, которые использует статья. Код оставлен в исходном виде, чтобы вы могли прямо вставить его в проект.

import './App.css';  
import { useEffect, useState } from 'react';  
import { addDoc, collection, setDoc, deleteDoc, doc, query, onSnapshot } from "firebase/firestore";  
import { firestore } from './firebase_setup/firebase';  
import { v4 as uuidv4 } from 'uuid';   

Компонент App:

function App() {  
  const [info, setInfo] = useState([])  
  const [isUpdate, setisUpdate] = useState(false)  
  const [docId, setdocId] = useState("")  
  const [detail, setDetail] = useState("")  
  const [ids, setIds] = useState([])  
    
  return (  
      
      
                 {           isUpdate ? (             <>               Update                                       ) : (Save)         }                {info.map((data, index)=>                {data}

                   Delete                               Edit                
      )}     
  ); }   export default App;

Запись данных в Firestore

Для добавления документов используйте addDoc или setDoc. addDoc удобен тем, что генерирует уникальный ID автоматически.

Пример импорта зависимостей показан выше. Теперь создаём обработчики для изменения поля и для отправки формы:

  const handledatachange = (e) => {  
    setDetail(e.target.value)  
  };  
   
  const submithandler = (e) => {  
    e.preventDefault()  
    const ref = collection(firestore, "test_data")  
   
    let data = {  
        uuid: uuidv4(),  
        testData: detail  
    }  
      
    try {  
        addDoc(ref, data)  
    } catch(err) {  
        console.log(err)  
    }  
   
    setDetail("")  
  }  

Замечания и когда лучше addDoc vs setDoc:

  • addDoc: удобен при вставке записей без заранее известного ID (например, ленты сообщений).
  • setDoc: нужен, когда вы контролируете ID (например, пользовательский профиль с ID = UID) или хотите перезаписать/объединить документ по известному пути.

Совет: храните служебные уникальные идентификаторы (uuid) внутри документа, если вам нужно независимое от Firestore ID поле для ссылок или кросс-системной синхронизации.

Чтение данных из Firestore

Используем useEffect и onSnapshot для подписки на изменения в коллекции. onSnapshot даёт snapshot, который автоматически обновляет клиент при изменении данных на сервере.

  useEffect(() => {  
    const getData = async () => {  
      const data = await query(collection(firestore, "test_data"));  
   
      onSnapshot(data, (querySnapshot) => {  
        const databaseInfo = [];  
        const dataIds = []  
   
        querySnapshot.forEach((doc) => {  
          databaseInfo.push(doc.data().testData);  
          dataIds.push(doc.id)  
        });  
   
        setIds(dataIds)  
        setInfo(databaseInfo)  
      });  
    }  
   
    getData()  
  }, [])  

Пояснения:

  • onSnapshot слушает изменения на сервере и вызывает колбэк с актуальным снимком.
  • setInfo заполняет массив значений для отображения, setIds хранит соответствующие идентификаторы документов для операций Update/Delete.

Отображение данных в DOM

Обновление данных в Firestore

Для обновления используйте setDoc с опцией { merge: true } чтобы не перезаписать весь документ.

const handleupdate = (e) => {  
    setisUpdate(true)  
    setDetail(e.target.parentNode.children[0].textContent)  
    setdocId(e.target.parentNode.children[0].getAttribute("data-id"))  
};  
   
const handlesubmitchange = async (e) => {  
    e.preventDefault()  
    const docRef = doc(firestore, 'test_data', docId);  
   
    const updatedata = await {  
      testData: detail  
    };  
   
    await setDoc(docRef, updatedata, { merge:true })  
        .then(console.log("Data changed successfully"))  
   
    setisUpdate(false)  
    setDetail("")   
}  

Логика: кнопка Edit наполняет input значением из выбранного документа, меняет isUpdate на true и сохраняет id документа. Кнопка Update отправляет изменения в Firestore.

Форма React с Firebase в DOM

Удаление данных из Firestore

Для удаления используйте deleteDoc, передав docRef по ID документа.

const handledelete = async (e) => {  
    const docRef = doc(firestore, 'test_data', e.target.parentNode.children[0].getAttribute("data-id"));  
   
    await deleteDoc(docRef)  
        .then(() => {  
          console.log(`${e.target.parentNode.children[0].textContent} has been deleted successfully.`)  
        })  
        .catch(error => {  
          console.log(error);  
        })  
}  

После выполнения deleteDoc удалённый документ исчезнет и из базы, и из локального списка благодаря подписке onSnapshot.

Практические рекомендации и лучшие практики

  1. Разделяйте логику доступа к Firestore в отдельные сервисные модули (api/firestore.js). Это упростит тестирование и замену логики.
  2. Ограничивайте правила безопасности Firestore (Security Rules) по необходимости: проверяйте auth.uid, права на запись и чтение.
  3. В продакшене избегайте хранения секретов в клиентском коде; используйте серверные функции (Cloud Functions) для чувствительных операций.
  4. Используйте пагинацию и индексирование для больших коллекций (limit, startAfter) — onSnapshot на большой коллекции может дорого обходиться.
  5. Обрабатывайте сетевые ошибки и показывайте пользователю статусы загрузки/ошибки.

Important: тестируйте правила безопасности отдельно от UI — включите эмуляторы Firebase для локальной отладки.

Отладка и распространённые ошибки

  • Неправильные правила Firestore — операция возвращает permission-denied.
  • Ошибка CORS/авторизации при попытке обратиться к приватным ресурсам — проверьте настройки аутентификации.
  • Несоответствие типов данных — Firestore строго хранит типы; главное поле testData должно быть строкой, если код ожидает строку.
  • Подписки onSnapshot множатся при повторном монтировании — отменяйте подписку при размонтировании компонента.

Пример отмены подписки:

useEffect(() => {
  const q = query(collection(firestore, "test_data"))
  const unsubscribe = onSnapshot(q, (snapshot) => { /* обработка */ })
  return () => unsubscribe()
}, [])

Малые методологии (cheat sheet)

  • Начать: create React app → firebase console → Firestore → получить конфиг → добавить firebase.js → установить зависимости.
  • Локально: запустить Firebase emulators для Firestore и Auth.
  • Производство: настроить Security Rules и ограничить права доступа.

Рольовые чеклисты

Разработчик frontend:

  • Инициализировал firebase.js и экспортировал firestore
  • Реализовал addDoc, onSnapshot, setDoc, deleteDoc
  • Добавил обработку ошибок и индикаторы загрузки

DevOps / SRE:

  • Настроил эмуляторы для тестов
  • Задеплоил правила безопасности и проверил разрешения

Product Owner:

  • Подтвердил сценарии CRUD и требования к безопасности
  • Утвердил ограничения на объём данных и требования к производительности

Решение выбора: addDoc или setDoc (дерево решений)

flowchart TD
  A[Нужен ли заданный ID?] -->|Да| B[Использовать setDoc]
  A -->|Нет| C[Использовать addDoc]
  B --> D{Требуется объединение полей?}
  D -->|Да| E[setDoc с {merge:true}]
  D -->|Нет| F[setDoc перезаписывает документ]
  C --> G[Firestore генерирует ID автоматически]

Критерии приёмки

  • Пользователь может создать запись через форму и увидеть её в списке.
  • Запись синхронизируется в реальном времени между несколькими клиентами.
  • Пользователь может отредактировать запись и увидеть обновления без перезагрузки.
  • Пользователь может удалить запись, и она пропадёт у всех клиентов.
  • Правила безопасности запрещают неавторизованный доступ.

Когда этот подход не подходит (контрпримеры)

  • Если вы нуждаетесь в сложных транзакциях между множеством сущностей — Firestore поддерживает транзакции, но для очень сложных бизнес-процессов лучше использовать серверный API.
  • Когда нужно гарантированное последовательное согласование с внешними сервисами — серверная логика даёт больше контроля.

Короткое резюме

  • Firestore + React позволяют быстро строить приложения с минимумом бэкенд-логики.
  • Используйте onSnapshot для реального времени, addDoc для быстрых вставок и setDoc для контролируемых обновлений.
  • Настройте правила безопасности и подумайте о хранении секретов для production.

Extras

  • Тестируйте в эмуляторе Firebase, прежде чем деплоить в прод.
  • Сохраняйте код доступа к Firestore в сервисах, а не в UI-логике.

Спасибо за чтение — теперь вы можете интегрировать Firestore в своё React-приложение и реализовать CRUD-сценарии с учётом безопасности и масштабируемости.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как добавить вершину в Blender
Blender

Как добавить вершину в Blender

Самодельный датчик движения HomeKit на ESP8266
Умный дом

Самодельный датчик движения HomeKit на ESP8266

Как делать заметки по роману в OneNote
Образование

Как делать заметки по роману в OneNote

Что установить на новом ПК — безопасная установка ПО
Программы

Что установить на новом ПК — безопасная установка ПО

Настройки сборки Unity и запуск проекта
Game Development

Настройки сборки Unity и запуск проекта

Управление адресной книгой Amazon
Руководство

Управление адресной книгой Amazon