Интеграция функций Convex через React-хуки

Вы уже создали таблицы и написали функции на стороне сервера. Теперь соединим бэкенд с интерфейсом. В Convex это работает как «живая связь»: как только данные в базе меняются, экран пользователя обновляется сам.

Client Component: включаем интерактивность

В Next.js компоненты по умолчанию «серверные» — они быстрые, но не умеют реагировать на клики или использовать хуки. Чтобы подключить Convex, нам нужен Client Component.

Просто добавьте в самую первую строку файла директиву:

"use client";

Без этой строки браузер не сможет «слушать» обновления базы данных, и приложение выдаст ошибку.


Получаем данные через useQuery

React-хуки — это инструменты, которые «подцепляют» логику Convex к вашему интерфейсу. Главный хук для чтения данных — useQuery.

Забудьте о ручном обновлении страницы или сложных запросах. Convex берет это на себя.

Как это выглядит в коде

Мы вызываем хук и передаем ему путь к функции из папки convex.

import { useQuery } from "convex/react";
import { api } from "../../convex/_generated/api";

export function TaskList() {
  // Подписываемся на данные. 
  // Переменная tasks обновится сама, если в базе что-то изменится.
  const tasks = useQuery(api.tasks.get);

  // Пока данные летят из облака, tasks будет undefined
  if (tasks === undefined) {
    return <p>Загрузка...</p>;
  }

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task._id}>{task.text}</li>
      ))}
    </ul>
  );
}

Важно: Если useQuery вернул undefined, значит, данные еще загружаются. Всегда добавляйте проверку, чтобы пользователь не видел пустой экран.


Меняем данные через useMutation

Для действий (нажать кнопку, отправить форму) используйте хук useMutation. В отличие от чтения, мутация срабатывает только тогда, когда вы её вызовете.

import { useMutation } from "convex/react";
import { api } from "../../convex/_generated/api";

export function AddTaskButton() {
  const createTask = useMutation(api.tasks.create);

  const handleClick = async () => {
    // Отправляем данные и ждем подтверждения
    await createTask({ text: "Запустить стартап" });
    console.log("Готово!");
  };

  return <button onClick={handleClick}>Добавить задачу</button>;
}

Мутации возвращают Promise, поэтому мы используем async/await. Это позволяет, например, очистить поле ввода сразу после того, как запись в базе подтверждена.


Почему это идеально для MVP?

Главная фишка связки React + Convex — реактивность.

  1. Вы вызываете useMutation.
  2. Данные в облаке меняются.
  3. Мгновенно обновляются все useQuery у всех пользователей, у которых открыто приложение.

Вам не нужно писать код для синхронизации состояния — всё просто работает «из коробки». 🚀

Чек-лист: как подключить функцию

  1. В начале файла стоит "use client".
  2. Импортированы useQuery или useMutation из convex/react.
  3. Импортирован объект api.
  4. Хук вызван внутри компонента.
  5. Для useQuery добавлена проверка на undefined.

Сейчас наш интерфейс выглядит как обычный текст. Чтобы ваш стартап выглядел профессионально и вызывал доверие, в следующей теме мы займемся Созданием интерфейса на компонентах shadcn/ui. Мы превратим сырые данные в красивые карточки и формы.