React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление Firebase в проект React казалось беспорядочным:

  • Вариант 1. Создайте компонент более высокого порядка, взаимодействуя с поставщиками и потребителями. Что? Но с Firebase это так просто!
  • Вариант 2. Инициализируйте Firebase в отдельном файле, настройте экспорт, включите его в начале проекта, а затем повторно включите в свои компоненты.

И хотя Вариант 1 по-прежнему является более сложным (осмелюсь сказать, лучшим) способом включения Firebase в проект React, который от него зависит, перехватчики React как бы смешивают эти два, но также делают его миллионным. раз чище и проще.

Создание поставщика / потребителя контекста React с помощью крючков React

В этом проекте мы предполагаем, что вашему приложению требуется Firebase для правильной работы. Под этим я подразумеваю: мы предполагаем, что вы хотите, чтобы Firebase была инициализирована в самом верху вашего кода и была доступна вам в любом месте вашего проекта, и что ваше приложение действительно не будет работать (если вообще), если Firebase не работает.

Конечно, это не обязательно. Я инициализирую Firebase таким образом в каждом проекте. Я просто даю вам небольшой контекст (плохая игра слов) относительно того, почему я структурирую это таким образом.

Мы коснемся трех файлов: основного index.js, нового utils/firebase.js, который мы создадим, и файла .env.production.

Перед началом работы: добавьте Firebase в свой проект!

Прежде всего, вы должны убедиться, что добавили в свой проект сам Firebase. Используя npm, это:

$ npm i firebase

Не используете npm? Я уверен, ты в этом разберёшься.

Добавление учетных данных Firebase в проект React

Шаг 1 очень простой. Когда вы создаете свой проект Firebase, Firebase предоставляет вам набор учетных данных для подключения к службам. Вам нужно включить их в свой проект React, и лучше всего через ваш .env файл. В этом случае мы создадим наш .env.production файл в корне проекта и добавим:

REACT_APP_FIREBASE_API_KEY=
REACT_APP_FIREBASE_AUTH_DOMAIN=
REACT_APP_FIREBASE_DATABASE_URL=
REACT_APP_FIREBASE_PROJECT_ID=
REACT_APP_FIREBASE_STORAGE_BUCKET=
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=
REACT_APP_FIREBASE_APP_ID=

Введите в них свои учетные данные, и вы готовы к шагу №2.

Создание поставщика контекста Firebase

Наш поставщик контекста - это то, что будет «удерживать» наше соединение Firebase и делать его доступным через остальную часть нашего приложения. (Держать - не совсем подходящий термин, но на простом английском языке - вот как вы можете думать об этом, чтобы все это имело смысл.)

На следующем шаге мы инициализируем Firebase. Как только мы это сделаем, нам больше не придется возвращаться и трогать этот файл. Поэтому я считаю это файлом служебной программы и обычно помещаю его в каталог utils. Следуя этой логике, создайте utils/firebase.js. (Вы можете называть это как хотите, но лучше быть явным.)

Первый шаг - импортировать в этот файл React и основное приложение Firebase. Мы также собираемся использовать ловушку контекста, поэтому одновременно импортируем useContext из React:

// utils/firebase.js
import React, { createContext } from 'react'
import app from 'firebase/app'

Теперь мы создадим нашего поставщика контекста. Мы собираемся инициализировать его значением null. Вы можете инициализировать его, как хотите, но я начинаю с null, чтобы позже проверить, существует ли мое соединение, с помощью простого оператора if. (Я поясню, когда покажу вам, как это сделать, еще в нескольких абзацах.)

Мы также собираемся экспортировать его сюда, чтобы мы могли использовать его в других файлах. Это тоже будет иметь смысл, когда мы перейдем к примеру использования. Но суть в том, что вам нужно экспортировать свой контекст, чтобы использовать его позже в других ваших компонентах.

// utils/firebase.js
...
const FirebaseContext = createContext(null)
export { FirebaseContext }

И теперь наш последний шаг: мы инициализируем саму Firebase, назначим ее нашему контексту и создадим компонент-оболочку, который мы можем использовать, чтобы обернуть наше приложение и сделать Firebase доступным повсюду.

// utils/firebase.js
...
export default ({ children }) => {
  if (!app.apps.length) {
    app.initializeApp({
      apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
      authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
      databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
      projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
      storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
      appId: process.env.REACT_APP_FIREBASE_APP_ID,
    })
  }
  return (
    <FirebaseContext.Provider value={ app }>
      { children }
    </FirebaseContext.Provider>
  )
}

Что ж, это быстро обострилось. Но на самом деле это очень просто. Давайте пройдемся по коду. Во-первых, мы создаем функциональный компонент, который принимает children в качестве опоры. children будет остальной частью вашего приложения, и вы увидите это на следующем этапе, когда мы будем использовать этот функциональный компонент.

Затем мы просто инициализируем Firebase, используя их код инициализации. Мне нравится проверять, что оно еще не инициализировано, поэтому я не получаю таких ошибок, как «Попытка инициализировать приложение, но оно уже было инициализировано». Мы используем учетные данные, которые мы добавили в наш .env файл поэтому мы можем легко переключать учетные данные в зависимости от нашей среды.

Наконец, мы возвращаем компонент, который можно использовать для обтекания всего нашего приложения. Мы присваиваем ему value из app, что является нашим инициализированным приложением Firebase. Это то, что мы получим позже, когда вызовем useContext в приведенном ниже примере.

Обертывание нашего приложения React с помощью нашего нового поставщика контекста Firebase

Последний шаг перед тем, как мы фактически используем Firebase, - это добавление этого нового провайдера в наш проект. Поскольку мы хотим, чтобы он был доступен для всего приложения, я помещу его в основной index.js файл следующим образом:

// All your other imports like React, React Router, whatever
import FirebaseProvider from 'utils/firebase'
ReactDOM.render(
  <FirebaseProvider>
    <App />
  </FirebaseProvider>,
  document.getElementById('root')
)

FirebaseProvider - это тот функциональный компонент, который мы создали на предыдущем шаге. Поскольку это экспорт по умолчанию из этого файла, вы можете называть его как хотите. Все, что находится внутри FirebaseProvider, теперь сможет получить доступ к нашему инициализированному приложению Firebase.

Вот и все! Теперь у вас есть Firebase, инициализированная и готовая к использованию в вашем проекте. Давайте посмотрим, как на самом деле это использовать.

Пример использования: получение записей из Firestore для отображения в вашем приложении

Допустим, у нас есть некоторый компонент списка в нашем приложении, и мы хотим получить записи из нашей shirts коллекции. Здесь мы воспользуемся тремя перехватчиками: useContext для подключения к Firebase, useState для обработки нашего списка элементов и useEffect потому, что мы хотим, чтобы наш компонент отображал начальное состояние, пока мы получаем наши записи.

import React, { useContext, useEffect, useState } from 'react'
import { FirebaseContext } from 'utils/firebase'
import 'firebase/firestore'
export default () => {
  const firebase = useContext(FirebaseContext)
  const [list, setList] = useState(null)
  const ref = firebase.firestore().collection(`shirts`)
  useEffect(() => {
    ref.get().then(snapshot => {
      if (!snapshot) {
        setList(l => [])
      } else {
        let shirts = []
        snapshot.forEach(shirt => {
          shirts.push({ key: shirt.id, ...shirt.data() })
        })
        setList(l => shirts)
      }
    }).catch(error => {
      // Handle the error
    })
  }, [])
  let listToDisplay
  if (list === null) {
    listToDisplay = (<li>Loading shirts...</li>)
  } else if (list.length === 0) {
    listToDisplay = (<li>No shirts found</li>)
  } else {
    listToDisplay = list.map(shirt => {
      return (<li key={ shirt.key }>{ shirt.name }</li>)
    })
  }
return (
    <ol>{ listToDisplay }</ol>
  )
}

Я хотел предоставить несколько более подробный пример, чтобы вы могли увидеть его в действии, но основные выводы здесь с точки зрения использования вашего соединения Firebase:

// Import the context we created
import { FirebaseContext } from 'utils/firebase'
// Import Firestore so this component can use it
import 'firebase/firestore'
// In your component, get the 'value' (the Firebase app instance) into a variable
// You can call it 'firebase', 'app' - whatever you want
const firebase = useContext(FirebaseContext)

Хотя может показаться, что это много, это только потому, что мы прошли каждую строчку. На самом деле для создания нашего поставщика контекста Firebase потребовалось всего 27 строк кода (плюс-минус несколько для межстрочного интервала), 3 строки кода для обертывания нашего приложения в Firebase и 3 строки кода для добавления к любому компоненту, в котором вы хотите использовать Firebase. (Плюс несколько .env записей.)

Дайте мне знать в комментариях, что вы собираетесь построить сейчас, чтобы вы могли легко добавить Firebase в любой проект React с помощью всего нескольких строк повторно используемого кода.