React + Supabase: простое CRUD-приложение

Краткое руководство по созданию простого CRUD-приложения на React с использованием Supabase как BaaS. Показываю, как создать проект Supabase, подключить клиент в React и реализовать операции Create, Read, Update и Delete с практическими примерами кода. В конце — рекомендации по безопасности, тестированию и альтернативные подходы.
Почему Supabase для фронтенд-приложений
Supabase — Backend-as-a-Service (BaaS). Такие провайдеры экономят время разработки. Вместо того чтобы писать и разворачивать отдельный бэкенд, вы получаете готовые сервисы: хранение данных, аутентификацию, realtime и серверные функции. Это удобно для прототипов, внутренних инструментов и многих публичных приложений.
Важно: BaaS не отменяет архитектурного проектирования. Он ускоряет разработку, но накладывает ограничения по гибкости и стоимости на больших масштабах.
Подготовка проекта Supabase
- Зарегистрируйтесь на сайте Supabase и войдите в панель управления.
- Нажмите кнопку New Project.
- Заполните данные проекта и создайте проект.
- Выберите раздел SQL Editor в левой панели.
- Выполните SQL-запрос ниже в SQL-редакторе, чтобы создать демонстрационную таблицу products:
create table products (
id bigint generated by default as identity primary key,
name text,
description text
);Примечание: этот пример использует минимальную схему для демонстрации CRUD. В продакшне добавляйте поля аудита (created_at, updated_at), индексы и ограничения целостности.
Создание React-приложения и переменные окружения
Создайте React-приложение (например, через create-react-app). В корне проекта создайте файл .env. На странице Supabase в разделе Settings → API скопируйте значения project URL и public anon key и вставьте их в .env:
REACT_APP_SUPABASE_URL = project URL
REACT_APP_SUPABASE_ANON_KEY = public anon keyУстановите клиентскую библиотеку Supabase:
npm install @supabase/supabase-jsНастройка клиента Supabase
В каталоге src создайте utils/SupabaseClient.js и добавьте:
import { createClient } from '@supabase/supabase-js';
const supabaseURL = process.env.REACT_APP_SUPABASE_URL;
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseURL, supabaseAnonKey);Этот код создаёт экземпляр клиента Supabase. Он использует URL и публичный anon-ключ. Через этот объект React будет выполнять запросы к базе.
Ссылка: можно хранить ключи в система CI/CD или secrets при деплое. Для локальной разработки .env достаточно.
Реализация CRUD в React
Ниже показан полный пошаговый пример добавления, чтения, обновления и удаления записей.
1. Добавление данных
Откройте src/App.js, удалите boilerplate и вставьте следующий код (фрагмент):
import { useState, useEffect } from 'react';
import ProductCard from './components/ProductCard';
import { supabase } from './utils/SupabaseClient';
import './App.css';
export default function App() {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
async function addProduct() {
try {
const { data, error } = await supabase
.from('products')
.insert({
name: name,
description: description
})
.single();
if (error) throw error;
window.location.reload();
} catch (error) {
alert(error.message);
}
}Объяснение: функция addProduct вставляет новую строчку в таблицу products. После успешной вставки выполняется перезагрузка страницы, чтобы обновить список записей. В продакшне лучше обновлять состояние локально вместо перезагрузки.
2. Чтение данных
Добавьте обработчик получения списка продуктов:
const [products, setProducts] = useState([]);
async function getProducts() {
try {
const { data, error } = await supabase
.from('products')
.select('*')
.limit(10);
if (error) throw error;
if (data != null) {
setProducts(data);
}
} catch (error) {
alert(error.message);
}
}
useEffect(() => {
getProducts();
}, []);useEffect вызывает getProducts при монтировании компонента. Метод select(‘*’) получает все поля, limit(10) ограничивает результат.
Далее рендерим форму добавления и список продуктов:
return (
<>
Store Products
Add products Data to the Supabase Database
setName(e.target.value)}
/>
setDescription(e.target.value)}
/>
Current Products in the Database
{products.map((product) => (
))}
>
);
}Совет: вместо window.location.reload() обновляйте состояние с помощью setProducts, это быстрее и даёт лучший UX.
3. Обновление и удаление
Создайте components/ProductCard.js и добавьте следующий код:
import { useState } from 'react';
import { supabase } from '../utils/SupabaseClient';
import './productcard.styles.css';
export default function ProductCard(props) {
const product = props.product;
const [editing, setEditing] = useState(false);
const [name, setName] = useState(product.name);
const [description, setDescription] = useState(product.description);
return (
{editing === false ? (
{product.name}
{product.description}
) : (
Editing Product
setName(e.target.value)}/>
setDescription(e.target.value)}/>
)}
);
}Добавьте функции updateProduct и deleteProduct ниже объявления состояний в том же файле:
async function updateProduct() {
try {
const { data, error } = await supabase
.from('products')
.update({
name: name,
description: description
})
.eq('id', product.id);
if (error) throw error;
window.location.reload();
} catch (error) {
alert(error.message);
}
}
async function deleteProduct() {
try {
const { data, error } = await supabase
.from('products')
.delete()
.eq('id', product.id);
if (error) throw error;
window.location.reload();
} catch (error) {
alert(error.message);
}
}Примечание: для улучшенного UX лучше обновлять локальное состояние и показывать подтверждение удаления вместо немедленной перезагрузки.
Когда такой подход не подходит
- Большой объём транзакционной логики на сервере. Если бизнес-логика сложная — лучше выделить бэкенд API.
- Особые требования к масштабированию и оптимизации запросов. BaaS накладывает ограничения по тонкой настройке.
- Строгие нормативные требования к хранению данных или разграничению доступа, которые нельзя реализовать на уровне клиента.
Если попадаете в один из этих сценариев, рассматривайте выделенный бэкенд или использование серверных функций (edge functions).
Альтернативные подходы
- Использовать Firebase (Firestore) — схожая модель BaaS с другим набором возможностей.
- Построить REST/GraphQL API на Node.js/Express или на Go/Python и хранить данные в PostgreSQL напрямую.
- Использовать серверныеless-функции (Vercel, Netlify) между клиентом и базой для дополнительного контроля и скрытия ключей.
Ментальные модели и эвристики
- Разделяй ответственность: клиент отвечает за UI и валидацию, сервер — за целостность и бизнес-правила.
- Принцип наименьших привилегий: давайте ключи с минимальными правами для публичного использования.
- Локальное состояние как источник правды: обновляйте UI через state, а не через перезагрузку страницы.
Факт-бокс: ключевые числа и рекомендации
- Подходит для: MVP, внутренних инструментов, прототипов.
- Рекомендация лимита выборки: по умолчанию ставьте limit и пагинацию (например, 10–50 записей за запрос).
- Безопасность: не храните секреты в исходниках; используйте serverless/edge для приватных операций.
Чек-лист ролей при разработке
- Разработчик фронтенда:
- Настроить .env и supabase клиент.
- Реализовать CRUD-логику и локальное обновление состояния.
- Добавить обработку ошибок и loading-индикаторы.
- Разработчик бэкенда / DevOps:
- Настроить правила RLS (Row Level Security) в Supabase при необходимости.
- Настроить резервное копирование и мониторинг.
- Инженер по безопасности:
- Проверить права anon-ключа.
- Настроить аудит доступа и логирование.
- Тестировщик:
- Покрыть сценарии: создание, чтение, обновление, удаление, ошибки валидации.
Критерии приёмки
- Создание: новая запись появляется в UI без дублирования.
- Чтение: список загружается и корректно отображает поля.
- Обновление: изменения сохраняются в базе и видны в UI.
- Удаление: запись удаляется и отсутствует в списке.
- Обработка ошибок: пользователь видит понятное сообщение при ошибке сети или валидации.
Шпаргалка и сниппеты
- Установка клиента:
npm install @supabase/supabase-js- Инициализация клиента (utils/SupabaseClient.js):
import { createClient } from '@supabase/supabase-js';
const supabaseURL = process.env.REACT_APP_SUPABASE_URL;
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseURL, supabaseAnonKey);- Пример запроса на выборку с пагинацией:
const { data, error } = await supabase
.from('products')
.select('*')
.range(0, 49); // первые 50 записей- Пример обновления конкретной записи:
const { data, error } = await supabase
.from('products')
.update({ name: 'Новое имя' })
.eq('id', 123);Безопасность и конфиденциальность
- Никогда не храните приватные ключи в клиентском коде. Используйте серверный слой или функции для операций, требующих elevated прав.
- Используйте Row Level Security (RLS) в Supabase для контроля доступа к строкам таблиц.
- Логируйте операции и настройки прав доступа. Это поможет расследовать инциденты.
- Если вы работаете с персональными данными, выполните соответствие требованиям GDPR/локального законодательства: хранение, право на удаление и экспорт данных.
Важно: anon-ключ предоставляет публичный доступ с разрешениями, заданными в политике Supabase. Настройте правила безопасности до выхода в продакшен.
Тестирование: кейсы и приёмка
- Проверить создание продукта с пустыми и некорректными полями.
- Проверить отображение списка при пустой базе.
- Проверить корректность обновления и отмены изменений.
- Проверить удаление и откат действий пользователя.
- Тестировать при плохом соединении и симулировать ошибки API.
Миграции и совместимость
- Для изменений схемы используйте SQL-скрипты в SQL Editor или систему миграций (например, через миграции в репозитории).
- При изменении полей аккуратно обновляйте клиентские формы и проверяйте backward-совместимость для старых записей.
Быстрый roadmap роста приложения
- MVP: клиентский CRUD с anon-ключом и простыми правилами.
- RLS и аутентификация: добавьте аутентификацию пользователей и правила доступа.
- Серверные функции: вынесите чувствительные операции в серверныеless-функции.
- Мониторинг и резервное копирование: настройте бэкапы и алерты.
Краткое резюме
Supabase позволяет быстро реализовать CRUD-приложение на React без отдельного бэкенда. Подходит для MVP и внутренних инструментов. Для продакшена обязательно настроить безопасность, RLS и миграции схемы.
Важно: используйте локальное обновление состояния вместо перезагрузки страницы для лучшего UX и меньшей нагрузки на сеть.
Ресурсы для дальнейшего изучения
- Документация Supabase: https://supabase.com/docs
- Больше примеров и шаблонов можно найти в официальном репозитории и сообществе Supabase.
Похожие материалы
Исправление ошибки «Не удалось создать раздел» в Windows 10
Как исправить ошибку «Подождите, пока программа удаляется»
Как исправить ошибку NSIS в Windows 11
Исправить ошибку Local Adapter Low Energy Controller