Перейти к основному содержимому

Интеграция React Gantt и Firebase

Этот учебник описывает, как создать диаграмму React Gantt, которая синхронизирует данные задач и связей между несколькими клиентами в реальном времени с помощью Firebase Firestore. Эта функциональность особенно полезна для:

  • инструментов управления проектами
  • приложений для командной работы
  • платформ планирования, где критически важна синхронизация нескольких пользователей

Вы узнаете, как:

  • настроить Firebase для обновлений в реальном времени
  • инициализировать и отрисовать Gantt
  • обрабатывать CRUD-операции (создание, чтение, обновление, удаление) с живой синхронизацией
  • эффективно обрабатывать изменения в реальном времени в состоянии Gantt

Вы можете проверить соответствующий пример на GitHub: DHTMLX React Gantt with Firebase Firestore Demo.

Шаг 1: Настройка проекта​

Начните с создания проекта на React + Vite.

Чтобы создать проект на React и перейти в каталог проекта, выполните следующие команды:

npm create vite@latest react-gantt-firebase -- --template react-ts
cd react-gantt-firebase

Установите необходимые зависимости следующим образом:

npm install firebase

Установка React Gantt​

Установите React Gantt, как описано в руководстве по установке React Gantt.

В этом примере мы используем пакет для оценки:

npm install @dhtmlx/trial-react-gantt

или

yarn add @dhtmlx/trial-react-gantt

Если вы уже используете Professional-пакет, замените @dhtmlx/trial-react-gantt на @dhx/react-gantt в командах и импортов.

Шаг 2: Настройка Firebase​

Сначала создайте проект Firebase, выполнив следующие шаги:

  • перейдите в Firebase Console
  • нажмите Create a project
  • введите имя проекта (например, react-gantt-firebase) и следуйте подсказкам по настройке

Затем настройте Firestore, выполнив шаги ниже:

  • перейдите в Firestore Database в панели управления вашим проектом Firebase
  • нажмите Create database
  • выберите желаемое расположение
  • начните в режиме test mode для упрощения разработки (не забудьте настроить правила безопасности перед продакшеном)
  • нажмите Create

После этого зарегистрируйте ваше веб-приложение следующим образом:

  • выберите Project Overview в боковой панели Firebase Console
  • нажмите значок веб-приложения </> для регистрации нового веб-приложения
  • укажите псевдоним приложения (например, react-gantt-firebase)
  • включите Firebase Hosting
  • нажмите Register app
  • скопируйте сгенерированную конфигурацию Firebase (она понадобится в вашем проекте)

Наконец, настройте Firebase в вашем проекте, как описано ниже:

  • вставьте конфигурацию Firebase в файл .env следующим образом:
VITE_FIREBASE_CONFIGURATION = {
"apiKey": "YOUR_API_KEY",
"authDomain":"react-gantt-firebase.firebaseapp.com",
"projectId": "react-gantt-firebase",
"storageBucket": "react-gantt-firebase.firebasestorage.app",
"messagingSenderId": "693536970600",
"appId": "1:693536970600:web:1b3fa4e4b032acaab368dd"
}
заметка

Замените плейсхолдер YOUR_API_KEY на реальные учетные данные вашего проекта Firebase.

  • создайте новый файл firebase.ts и инициализируйте Firebase и Firestore. Также экспортируйте ссылки на коллекции, как показано ниже:
import { initializeApp } from "firebase/app";
import { getFirestore, collection, query } from "firebase/firestore";

const firebaseConfig = JSON.parse(import.meta.env.VITE_FIREBASE_CONFIGURATION);

initializeApp(firebaseConfig);
const db = getFirestore();
const tasksCollection = collection(db, "tasks");
const linksCollection = collection(db, "links");
const tasksQuery = query(tasksCollection);
const linksQuery = query(linksCollection);

export { db, tasksQuery, linksQuery, tasksCollection, linksCollection };

Шаг 3: Создайте компонент Gantt​

Для начала настройте основной компонент Gantt с React state для задач и связей со следующей конфигурацией:

const [tasks, setTasks] = useState<Task[]>([]);
const [links, setLinks] = useState<Link[]>([]);

const templates: GanttTemplates = {
parse_date: (date) => new Date(date),
format_date: (dateString) => dateString.toISOString(),
};

const config: GanttConfig = {
auto_scheduling: true,
};

В приведённом выше фрагменте:

  • Templates

Шаблоны позволяют контролировать, как даты парсятся и форматируются внутри компонента Gantt. Поскольку Firestore хранит даты в виде строк, нам нужно преобразовать их обратно в объекты Date (parse_date) и корректно форматировать их для хранения (format_date).

  • Config

Опция auto_scheduling включает автоматическую перерасчёт зависимых задач, когда родительская задача перемещается или изменяется. Это полезно в сценариях управления проектами.

Теперь создайте обработчики состояния для управления внутренним состоянием Gantt, как показано ниже:

const createStateHandlers = <T extends { id: string | number }>(
setState: React.Dispatch<React.SetStateAction<T[]>>
): EntityHandler<T> => ({
added: (item) => setState((prev) => (prev.find((i) => i.id === item.id) ? prev : [...prev, item])),
modified: (item) => setState((prev) => prev.map((i) => (i.id === item.id ? { ...i, ...item } : i))),
removed: (item) => setState((prev) => prev.filter((i) => i.id !== item.id)),
});

const taskHandlers = createStateHandlers<Task>(setTasks);
const linkHandlers = createStateHandlers<Link>(setLinks);

Это обеспечивает единый способ обновления локального состояния при изменениях данных Firebase.

Поскольку мы работаем с двумя типами сущностей — задачами и связями, можно создать единый конфигурационный объект, который будет обрабатывать оба типа вместо дублирования кода. Этот объект сопоставляет каждому типу сущности его коллекцию Firestore, путь API и обработчики состояния. Смотрите следующий фрагмент кода:

const entityConfig = {
task: {
collection: tasksCollection,
path: "tasks",
handlers: taskHandlers,
},
link: {
collection: linksCollection,
path: "links",
handlers: linkHandlers,
},
};

Обзор структуры проекта​

Вы можете посмотреть итоговую структуру проекта в следующей схеме:

src/
├── App.tsx # Точка входа
├── App.css # Стили
├── components/
│ └── Gantt/
│ ├── Gantt.tsx # Основная логика
│ └── types.ts # Определения типов
├── config/
│ └── firebase.ts # Настройка Firebase
└── main.tsx # Корень React

Шаг 4: Загрузка начальных данных​

Когда компонент монтируется, следует загрузить все задачи и связи следующим образом:

useEffect(() => {
let unsubscribeTasks: () => void;
let unsubscribeLinks: () => void;

(async () => {
const tasksSnap = await getDocs(tasksQuery);
const bulkTasks = tasksSnap.docs.map(processEntity) as Task[];
const linksSnap = await getDocs(linksQuery);
const bulkLinks = linksSnap.docs.map(processEntity) as Link[];

setTasks(bulkTasks);
setLinks(bulkLinks);

const unsubscribers = watchRealtime();
unsubscribeTasks = unsubscribers.unsubscribeTasks;
unsubscribeLinks = unsubscribers.unsubscribeLinks;
})();

return () => {
if (unsubscribeTasks) unsubscribeTasks();
if (unsubscribeLinks) unsubscribeLinks();
};
}, []);

Чтобы преобразовать документы Firebase в объекты, совместимые с Gantt, используйте processEntity, как приведено ниже:

const processEntity = (docSnapshot: QueryDocumentSnapshot): Task | Link => {
return { ...docSnapshot.data(), id: docSnapshot.id };
};

Шаг 5: Настройка синхронизации в реальном времени​

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

function watchRealtime() {
let tasksLoaded = false;
let linksLoaded = false;

const unsubscribeTasks = onSnapshot(tasksQuery, (querySnapshot) => {
if (!tasksLoaded) {
tasksLoaded = true;
return;
}

handleRealtimeUpdates(querySnapshot, "task");
});

const unsubscribeLinks = onSnapshot(linksQuery, (querySnapshot) => {
if (!linksLoaded) {
linksLoaded = true;
return;
}
handleRealtimeUpdates(querySnapshot, "link");
});

return { unsubscribeTasks, unsubscribeLinks };
}

Первый вызов onSnapshot возвращает начальные данные, изменения — нет, поэтому в watchRealtime мы игнорируем первый вызов (поскольку начальные данные уже загружены).

Обработка изменений в реальном времени​

Вы можете обрабатывать изменения в реальном времени с помощью функции, приведённой в следующем примере кода:

function handleRealtimeUpdates(querySnapshot: QuerySnapshot, type: GanttEntityType) {
const config = entityConfig[type];
if (!config) throw new Error(`Unknown entity type: ${type}`);
const { handlers } = config;
querySnapshot.docChanges().forEach((change) => {
if (change.doc.metadata.hasPendingWrites) return;
const handler = handlers[change.type];
if (!handler) {
throw new Error(`Unknown change type: ${change.type}`);
}
const data = processEntity(change.doc);
(handler as (data: Task | Link) => void)(data);
});
}

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

docChanges() возвращает список изменений (added, modified, removed), внесённых в коллекцию Firestore с момента последнего снимка. Firestore предоставляет тип изменения (added, modified, removed), и мы маршрутизируем его к соответствующему обработчику для обновления состояния React.

Шаг 6: Реализация операций CRUD с Firebase​

Чтобы обрабатывать запросы на создание, обновление и удаление из компонента Gantt, используйте логику метода data.save, приведённой ниже:

const data = {
save: async (
entity: GanttEntityType,
action: GanttActionType,
raw: any, id: string | number
) => {
try {
const config = entityConfig[entity];
if (!config) throw new Error(`Unknown entity type: ${entity}`);

const { collection, path, handlers } = config;
const ref = doc(db, path, id.toString());

switch (action) {
case "create": {
const addedDoc = await addDoc(collection, raw);
handlers.added({ ...raw, id: addedDoc.id });
break;
}
case "update": {
await updateDoc(ref, raw);
handlers.modified(raw);
break;
}
case "delete": {
await deleteDoc(ref);
handlers.removed(raw);
break;
}
default:
throw new Error(`Unknown action type: ${action}`);
}
} catch (err) {
console.error(`Failed to ${action} ${entity}:`, err);
}
},
};

Firebase будет автоматически распространять эти изменения на всех подключённых клиентов с помощью слушателей снимков.

Затем отобразите диаграмму Gantt следующем коде:

return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
<ReactGantt
tasks={tasks}
links={links}
templates={templates}
config={config}
data={data}
/>
</div>
);

Свойство data соединяет встроенное редактирование Gantt с логикой сохранения Firebase, приведённой выше.

Шаг 7: Развертывание проекта в Firebase​

Как только проект будет полностью работоспособен и синхронизация в реальном времени функционирует корректно, вы можете развернуть его, чтобы он стал общедоступным в интернете. Есть два способа развернуть проект: через Firebase CLI и через консоль Firebase.

Развертывание через Firebase CLI (Рекомендуется)​

Это самый эффективный метод, особенно если вы планируете регулярно обновлять проект. Выполните следующие шаги:

1. Сначала, если CLI Firebase ещё не установлен, установите его с помощью команды:

npm install -g firebase-tools

2. Затем выполните вход в Firebase с помощью следующей команды:

firebase login

3. После этого инициализируйте Firebase в вашем проекте следующей командой:

firebase init

Во время инициализации выполните следующие шаги:

  • выберите Hosting (также можно выбрать Firestore, если вы ещё не настроили его)
  • укажите папку сборки (например, dist или build, в зависимости от вашего vite.config.ts или package.json)
  • при вопросе об конфигурации как SPA (Single Page App) выберите Yes, чтобы все маршруты обслуживались через index.html

4. Теперь соберите проект следующей командой:

npm run build

Он сгенерирует готовые к продакшн-использованию файлы в папке dist (или build).

5. Наконец, разверните в Firebase, выполнив следующую команду:

firebase deploy

После завершения развертывания Firebase предоставит вам ссылку на размещённый проект.

Быстрое развёртывание через Firebase Console​

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

1. Соберите проект, выполнив команду ниже:

npm run build

2. Перейдите в Firebase Hosting → Ваш проект → Hosting

3. Нажмите "Get Started" или "Upload"

4. Загрузите содержимое папки dist (или build)

5. Подтвердите загрузку — Firebase предоставит вам публикуемый URL для вашего сайта

Заключение​

В этом руководстве мы создали реальную диаграмму Gantt с синхронизацией через Firebase. Вы узнали, как:

  • подключить React Gantt к Firebase Firestore
  • настроить подписку в реальном времени на Firestore
  • обрабатывать события создания, обновления и удаления с мгновенной синхронизацией между несколькими клиентами

Такой подход идеально подходит для совместных инструментов управления проектами, где всем пользователям нужно видеть живые обновления без обновления страницы.

Need help?
Got a question about the documentation? Reach out to our technical support team for help and guidance. For custom component solutions, visit the Services page.