При прототипировании идеи рекомендуется упрощать и создавать только минимальные основные функции, необходимые для запуска продукта на рынке. Это поможет вам определить, соответствует ли ваше приложение требованиям рынка, прежде чем тратить время и деньги на продукт, который никому не интересен. Это называется «минимально жизнеспособным продуктом» (MVP). В этом руководстве вы узнаете, как создать MVP с помощью React и Firebase, платформы «бэкенд как услуга».
Чтобы обеспечить наибольшую ценность, мы не будем разрабатывать приложение React + Firebase шаг за шагом. Вместо этого я разберу рабочий прототип и объясню ключевые концепции, используя псевдоподобный язык программирования. Фактический код довольно многословен, так как это в основном интерфейсная логика, предназначенная для работы со многими аспектами, такими как управление состоянием, адаптивный дизайн пользовательского интерфейса и доступность.
Моя цель — показать вам архитектурный дизайн создания
Почему Firebase?
Если вы хотите создать
Если бы вы выбрали лучшее в своем классе для каждой службы, у вас была бы довольно высокая кривая обучения, чтобы выяснить, как заставить все эти службы работать вместе в вашем приложении. Вы также подвергаете свой продукт ряду угроз безопасности, поскольку существует несколько конечных точек, к которым подключается ваш продукт для работы. Существуют меры по защите вашего приложения, но большинство разработчиков не знают, какие проблемы безопасности необходимо устранить.
Firebase — это серверная платформа как услуга, которая удобно предоставляет ряд основных услуг под одной крышей. Это сокращает кривую обучения, а также упрощает создание безопасных
Эти службы Firebase включают в себя:
аутентификация
база данных
место хранения
облачные функции
аналитика
хостинг
Предпосылки
Обратите внимание, что это руководство написано для разработчиков React среднего и продвинутого уровня, которые хотят быстро научиться использовать Firebase для своих проектов. Я предоставил несколько дополнительных тем, с которыми вам необходимо ознакомиться, прежде чем продолжить:
Реагировать и TailwindCSS
Реагировать на запрос
Vite — лучшая
План проекта Firebase
Проект, который мы рассмотрим, представляет собой простую
диаграмма отношений сущностей
Логика приложения была организована в:
экранные контейнеры (страницы или представления)
презентационные компоненты (формы, таблицы)
компоненты макета (нижний колонтитул, панель навигации)
общие компоненты пользовательского интерфейса (оповещения, модальные окна, заголовки страниц)
Сервисы Firebase (база данных, хранилище)
Сценарии конфигурации Firebase (внутренние соединители)
Ниже приведена иллюстрация основной архитектуры проекта:
схема архитектуры приложения
Мы будем использовать следующую структуру папок для организации нашего кода:
├── components
│ ├── entity (e.g. book)
│ │ ├── Card.jsx (→ BookCard)
│ │ ├── Detail.jsx (→ BookDetail)
│ │ ├── Form.jsx
│ │ └── List.jsx
│ └── ui
│ └── Component.jsx (e.g. PageHeader, Alert)
├── layout
│ ├── Footer.jsx
│ └── Navbar.jsx
├── screens
│ ├── entity
│ │ ├── Detail.jsx (→ ScreenBookDetail)
│ │ ├── Form.jsx (→ ScreenBookForm)
│ │ └── List.jsx
│ ├── category
│ │ ├── Form.jsx
│ │ └── List.jsx
│ ├── Home.jsx
│ └── NotFound.jsx
└── services
└── Service.js (e.g. Database, Storage)
Символ →обозначает пример того, как называется функциональный компонент. Ознакомьтесь с этим руководством для получения дополнительной информации о соглашениях об именах для интерфейсных приложений.
Настройка проекта Firebase
Проект, который мы будем использовать, был создан с использованием шаблона Vite + React. Чтобы настроить проект в рабочей области, просто откройте терминал и выполните следующее:
# Clone project
git clone git@github.com:sitepoint-editors/sitepoint-books-firebase.git
author_id (ссылка) /авторы/{идентификатор места} /авторы/{идентификатор места}
category_id (ссылка) /categories/{идентификатор места} /categories/{идентификатор места}
Описание Это простое и увлекательное руководство — идеальное место для начала вашего пути к программированию. Вы будете учиться программировать на JavaScript — самом популярном языке программирования на Земле, — но методы, которые вы освоите, дадут вам основу для дальнейшего использования и на других языках. Эта книга представляет собой сборник подробных руководств по некоторым инструментам, наиболее часто используемым в науке о данных, таким как Pandas и PySpark, а также обзор некоторых навыков, которые вам понадобятся как специалисту по данным.
См. скриншот ниже в качестве примера того, как настроить структуру базы данных.
облачная база данных firestore
Запуск сервера разработки
Теперь, когда база данных заполнена, мы можем выполнить npm run devи перейти localhost:3000к взаимодействию с проектом. Обратите внимание, что это прототип приложения, созданный для обучения, и не все функции реализованы полностью.
подробное описание книги приложений
Логика проекта Firebase
Давайте теперь начнем разбирать проект, чтобы вы могли узнать, как внешние интерфейсы построены для подключения и взаимодействия с серверной частью Firebase. Основное внимание в этом руководстве будет уделено логике управления состоянием. Если вы не знакомы с кодом пользовательского интерфейса, используемым в этом проекте Firebase, обратитесь к следующей документации по библиотекам пользовательского интерфейса, используемым в проекте:
TailwindCSS и плагины: основной
HeadlessUI: небольшая коллекция нестилизованных компонентов пользовательского интерфейса.
HeroIcons: коллекция
DaisyUI: библиотека компонентов TailwindCSS
React Hook Form: формировать государственную библиотеку
Ага: библиотека проверки формы
Маршрутизация
Создание интерфейса CRUD для проекта, в котором задействовано более двух объектов, может быстро усложниться. Для маршрутизации я использовал React Router и реализовал структуру маршрутизации, используя стандартизированный синтаксис. То есть:
список маршрутов: /{entity}
создать маршрут: /{entity}/create
изменить маршрут: /{entity}/edit/: id
подробный маршрут: /{entity}/: id
Вот упрощенное представление о том, как маршрутизация была реализована в App.jsx:
import React from «react»;
import { Route, Switch } from «
// Layout components
import Footer from «@/layout/Footer»;
import Navbar from «@/layout/Navbar»;
// Screen (pages or views) containers
import Home from «@/screens/Home»;
import NotFound from «@/screens/NotFound»;
import ScreenBookList from «@/screens/book/List»;
import ScreenBookForm from «@/screens/book/Form»;
import ScreenBookDetail from «@/screens/book/Detail»;
function App () {
return (
New Author
...
...
<Link to={`/author/edit/${author.id}`} title={`Edit ${author.name}`}>
|
) ;
}
Контейнер ScreenAuthorFormпредназначен для обработки вариантов использования автора как создания, так и обновления. В случае обновления нам нужно получить idиз
import { useParams } from '
function ScreenAuthorForm () {
const { id } = useParams () // retrieve id from url parameters
// fetch document
const { data, isLoading, error, status } = useQuery (
['author’, { id }],
AuthorService.getOne
)
// Render create form
if (! id) {
return (
<>
</>
)
}
// Render update form
return (
<>
<>
)
}
Мы не будем вдаваться в подробности того, как устроена форма, но я предоставлю вам упрощенную версию AuthorFormкомпонента:
import React, { useState, useEffect } from «react»;
import { useForm } from «
function AuthorForm ({ values, submit }) {
// initialize
const { register, reset, handleSubmit } = useForm () ;
// populate form fields
useEffect (() => {
reset (values) ;
}, [values]) ;
// call container submit handler to save new/updated values
const onSubmit = (submittedData) => {
submit (submittedData) ;
};
return (
Cancel
) ;
}
Встроенные комментарии должны объяснять основные разделы кода. Обратитесь к документации React Hook Form, чтобы узнать, как работает библиотека. Мы не смотрели на submitфункцию, поэтому давайте сделаем это сейчас в ScreenAuthorFormконтейнере:
import { useParams, Redirect } from '
import { useQuery, useMutation, useQueryClient } from '
function ScreenAuthorForm () {
const { id } = useParams ()
const queryClient = useQueryClient ()
// call the database service to create or update document depending on presence of id
const saveData = (data) => {
if (id) {
return AuthorService.update (id, data)
} else {
AuthorService.create (data)
}
}
// create mutation
const mutation = useMutation ((data) => saveData (data), {
onSuccess: () => {
if (id) queryClient.invalidateQueries (['author’, { id }])
},
})
// track mutation status i.e. return true after successful mutation
const { isSuccess } = mutation
// define submit action handler to be passed down as prop to AuthorForm
const onSubmit = async (submittedData) => {
mutation.mutate (submittedData)
}
// if mutation is successful, redirect to ScreenAuthorList
if (isSuccess) {
return
}
// render create and update form
return (
...
...
)
...
}
Встроенные комментарии должны объяснять, что делает каждый блок кода. Обратитесь к документации по мутациям React Query, чтобы понять, как это работает. В следующем разделе мы рассмотрим, как мы можем отображать изображения, хранящиеся в службе облачного хранилища Firebase.
Отображение изображений
В этом разделе мы будем использовать CategoryCardдля демонстрации рендеринга изображений.
список категорий приложений
Напоминаем, вот пример данных категории:
{
«name»: «javascript»,
«cover»: «categories/javascript.png»
}
Если вы перейдете к одному из изображений, которые вы загрузили в облачное хранилище, вы увидите
gs: //
Эта ссылка не может быть обработана браузером. Его необходимо преобразовать в ссылку для скачивания в формате HTTP. Для этого нам нужно импортировать пакет, который позволяет нашему приложению взаимодействовать со службой Firebase Storage. Это делается в firebase.js:
...
import 'firebase/storage’
...
export const storage = app.storage ()
Далее мы можем импортировать storageэкземпляр и определить функцию, которая будет выполнять это преобразование. Это было сделано в StorageService.js:
import { storage } from «.../firebase»;
const storageRef = storage.ref () ; // access the default bucket
// accepts file path in the format `folder/filename.ext`
const getImageURL = async (filePath) => {
const url = await storageRef.child (filePath).getDownloadURL () ;
return url;
};
const StorageService = {
getImageURL,
};
export default StorageService;
Теперь, когда мы настроили службу, которая будет обрабатывать для нас преобразование
import React, { useEffect, useState } from «react»;
import { Link } from «
import StorageService from «.../... /services/StorageService»;
function CategoryCard ({ category }) {
const [imageLink, setImageLink] = useState () ;
// download the image link
useEffect (async () => {
const url = await StorageService.getImageURL (category.cover) ;
setImageLink (url) ;
}, [category]) ;
return (
<Link to={`/category/edit/${category.id}`}>
) ;
}
export default CategoryCard;
К сожалению, это совсем немного работы только для отображения изображения. Мы поговорим об этом позже в резюме. А пока давайте рассмотрим другую проблему, когда вам нужно разрешить пользователям выбирать из доступного списка файлов.
Список файлов
При работе с изображениями мы можем дать пользователям возможность загружать новые или выбирать из существующих. Обычно современные интерфейсы имеют браузеры активов, которые позволяют вам делать и то, и другое. Для простоты мы просто будем использовать базовый ввод для выбора из раскрывающегося списка.
Раскрывающееся меню категории приложений Firebase
Чтобы получить список файлов из облачного хранилища из определенной папки, нам нужна функция, которая может справиться с этой задачей в StorageService.js:
// input: folder name
// output: list of fileNames in array format
const listFiles = async (folder) => {
const listRef = storageRef.child (folder) ;
const res = await listRef.listAll () ;
const list = res.items.map ((itemRef) => itemRef. _delegate. _location.path_) ;
return list;
};
const StorageService = {
...listFiles,
};
Теперь, когда listFilesфункция определена, мы можем вызвать ее из CategoryForm компонента:
import React, { useState, useEffect } from «react»;
import StorageService from «.../... /services/StorageService»;
function CategoryForm ({ values, action }) {
const [coverOptions, setCoverOptions] = useState ([]) ;
// Get list of available images from cloud storage
useEffect (async () => {
const availableFiles = await StorageService.listFiles («categories») ;
setCoverOptions (availableFiles) ;
}, []) ;
return (
) ;
}
Используя асинхронную useEffectфункцию, мы можем получить имена файлов, а затем заполнить поле выбора через coverOptionsсостояние. В следующем разделе мы рассмотрим, как разрешать связи между документами.
Разрешение отношений документов
Если вспомнить bookструктуру сущности, она содержала ссылочные поля с именами author_idи category_id. Для большинства систем баз данных и библиотек ORM существует возможность заполнения ссылок значениями, так что для загрузки всех необходимых данных требуется только один запрос.
К сожалению, для базы данных Firestore вам необходимо выполнить дополнительные запросы для загрузки ссылочных документов. Нам нужно определить конкретную функцию для этого в DatabaseService.js:
class DatabaseService {
...
getReference = async (documentReference) => {
const res = await documentReference.get ()
const data = res.data ()
if (data && documentReference.id) {
data.uid = documentReference.id
}
return data
}
...
}
Теперь, когда функция определена, мы можем полностью загрузить документ со справочными полями. См. BookDetailкомпонент в качестве примера:
import { BookService } from «@/services/DatabaseService»;
function BookDetail ({ book }) {
const [author, setAuthor] = useState () ;
const [category, setCategory] = useState () ;
// Resolve book.author_id document reference
useEffect (async () => {
const authorRef = await BookService.getReference (book.author_id) ;
setAuthor (authorRef) ;
}, [book]) ;
// Resolve book.category_id document reference
useEffect (async () => {
const categoryRef = await BookService.getReference (book.category_id) ;
setCategory (categoryRef) ;
}, [book]) ;
return (
...
{category && {category.name}}
...
{author && By {author.name}}
...
) ;
}
В приведенном выше примере мы используем асинхронные useEffectперехватчики для выполнения дополнительных запросов. В следующем разделе мы начнем завершать статью.
Другие сервисы Firebase
К сожалению, существует множество сервисов Firebase, которые я не смогу описать в этой статье. Эти серверные службы очень важны для создания вашего приложения MVP Firebase. Итак, я сделаю краткий обзор некоторых из них:
Аутентификация. Этот сервис позволяет легко добавлять функции входа в ваше приложение Firebase. Он поддерживает электронную почту, учетные записи социальных сетей, GitHub и даже методы аутентификации по SMS. Аутентификация Firebase тесно интегрируется с другими сервисами Firebase и может быть легко интегрирована с вашим пользовательским сервером.
Облачные функции. Это сервис, который позволяет вам писать и выполнять внутренний код в ответ на события, вызванные функциями Firebase и
Хостинг. Это сервис, предоставляющий хостинг
Аналитика. Вы можете использовать Google Analytics для сбора данных об использовании и поведении для вашего
Как упоминалось ранее, настроенные нами правила безопасности разрешают общедоступный доступ для чтения и записи к нашему серверному интерфейсу. Чтобы узнать, как защитить свою учетную запись Firebase, я рекомендую ознакомиться с правилами безопасности. Обратите внимание, что вы также должны реализовать аутентификацию Firebase в своем приложении, чтобы разрешить безопасный доступ к данным.
Резюме
Подводя итог, вы научились:
структурировать и организовывать интерфейсный код
зарегистрировать приложение Firebase
заполнить базу данных и хранилище Firestore
получить как данные, так и файлы из серверной части Firebase
Связывание коллекций во внешнем пользовательском интерфейсе
Есть еще так много сервисов Firebase, которые мы еще не затронули. Как видите, проще создать MVP, в котором все серверные службы находятся под одной крышей. Мы установили только одну библиотеку Firebase, которая предоставляет большинство внутренних функций, необходимых большинству MVP.
Мы также не рассмотрели расширения Firebase, которые являются дополнительными функциями, которые мы можем легко реализовать для расширения нашего приложения Firebase. Примеры таких расширений включают:
Изменить размер изображений
Поиск с Алголией
Полосатые платежи
Сократить
И многое другое. Если вам понравился Firebase и вам нужна более мощная база данных, вы можете попробовать Supabase — альтернативу с открытым исходным кодом, предлагающую базу данных PostgreSQL. Тем не менее, Supabase является новым продуктом на рынке и на момент написания статьи находится на стадии