React напрямую не подключается к MySQL. Браузерный код нельзя пускать в базу данных: логин и пароль окажутся у пользователя. Правильная схема — React делает HTTP-запросы к backend, а backend работает с MySQL.
Архитектура
React в браузере -> HTTP API -> Node.js Express -> MySQL
Создать таблицу
CREATE DATABASE react_app;
USE react_app;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email) VALUES
('Алиса', 'alice@example.com'),
('Боб', 'bob@example.com');
Backend на Express
mkdir backend
cd backend
npm init -y
npm install express mysql2 cors dotenv
const express = require('express');
const mysql = require('mysql2/promise');
const cors = require('cors');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.json());
const pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'react_app',
});
app.get('/api/users', async (req, res) => {
const [rows] = await pool.query('SELECT id, name, email FROM users ORDER BY id DESC');
res.json(rows);
});
app.post('/api/users', async (req, res) => {
const { name, email } = req.body;
const [result] = await pool.query(
'INSERT INTO users (name, email) VALUES (?, ?)',
[name, email]
);
res.status(201).json({ id: result.insertId, name, email });
});
app.delete('/api/users/:id', async (req, res) => {
await pool.query('DELETE FROM users WHERE id = ?', [req.params.id]);
res.json({ ok: true });
});
app.listen(3001, () => {
console.log('API started on http://localhost:3001');
});
React frontend
import { useEffect, useState } from 'react';
const API = 'http://localhost:3001/api';
function App() {
const [users, setUsers] = useState([]);
const [name, setName] = useState('');
const [email, setEmail] = useState('');
async function loadUsers() {
const response = await fetch(`${API}/users`);
const data = await response.json();
setUsers(data);
}
useEffect(() => {
loadUsers();
}, []);
async function addUser(event) {
event.preventDefault();
await fetch(`${API}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email }),
});
setName('');
setEmail('');
loadUsers();
}
return (
<main>
<form onSubmit={addUser}>
<input value={name} onChange={e => setName(e.target.value)} placeholder="Имя" />
<input value={email} onChange={e => setEmail(e.target.value)} placeholder="Email" />
<button>Добавить</button>
</form>
{users.map(user => (
<p key={user.id}>{user.name} — {user.email}</p>
))}
</main>
);
}
Безопасность
- Не храните пароль MySQL в React-коде.
- Используйте параметры запроса, а не склейку SQL строк.
- Проверяйте входные данные на backend.
- Ограничьте CORS доменом frontend в production.
- Для авторизации добавьте сессии или JWT на backend.
Добавить обновление пользователя
app.put('/api/users/:id', async (req, res) => {
const { name, email } = req.body;
await pool.query(
'UPDATE users SET name = ?, email = ? WHERE id = ?',
[name, email, req.params.id]
);
res.json({ id: Number(req.params.id), name, email });
});
Файл .env для backend
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=secret
DB_NAME=react_app
PORT=3001
Файл .env должен лежать на backend и не должен попадать в публичный репозиторий. В React-папку эти значения класть нельзя.
Структура production-проекта
В production frontend обычно собирают в статические файлы и отдают через Nginx. Backend запускают отдельным Node.js процессом или контейнером. MySQL находится отдельно, а доступ к нему открыт только backend-серверу.
- React: npm run build.
- Nginx: отдаёт dist и проксирует /api.
- Express: проверяет данные и выполняет SQL.
- MySQL: недоступен напрямую из браузера.
- Переменные окружения: только на сервере.
Что важно не перепутать в React + MySQL
Главная ошибка в этой теме — пытаться подключить браузер напрямую к базе. React должен общаться с backend API, а уже backend работает с MySQL. Так вы не раскрываете пароль базы и можете нормально проверять права пользователя.
В учебных примерах это разделение иногда кажется лишним, но в реальном проекте оно обязательно. Backend проверяет права, валидирует входные данные, прячет пароль базы и возвращает frontend только тот JSON, который можно показать пользователю.
Правильная схема
- React отправляет fetch-запросы на /api;
- Express проверяет входные данные;
- backend выполняет SQL через mysql2;
- пароль MySQL хранится в .env на сервере;
- браузер никогда не видит доступы к базе.
Что добавить перед production
Минимальный учебный пример не закрывает безопасность полностью. Перед реальным запуском нужны авторизация, валидация данных, ограничение CORS, нормальная обработка ошибок и логирование backend-запросов.
Как развивать пример
После списка пользователей добавьте редактирование, поиск, пагинацию и обработку duplicate email. Эти задачи быстро показывают, зачем нужен backend-слой, а не прямой доступ к MySQL.



