React Gantt und Firebase-Integration
Dieses Tutorial beschreibt, wie man ein React Gantt Diagramm baut, das Aufgaben- und Verknüpfungsdaten über mehrere Clients in Echtzeit mit Firebase Firestore synchronisiert. Diese Funktion ist besonders nützlich für:
- Projektmanagement-Tools
- Team-Kollaborations-Apps
- Planungsplattformen, bei denen Multi-User-Synchronisation kritisch ist
Sie lernen, wie man:
- Firebase für Echtzeit-Updates einrichtet
- das Gantt-Diagramm initialisiert und rendert
- CRUD-Operationen (Erstellen, Lesen, Aktualisieren, Löschen) mit Live-Synchronisation durchführt
- Echtzeit-Änderungen im Gantt-Zustand effizient verarbeitet
Sie können das entsprechende Beispiel auf GitHub prüfen: DHTMLX React Gantt mit Firebase Firestore Demo.
Schritt 1: Projektsetup
Starten Sie damit, ein React + Vite-Projekt zu erstellen.
Um ein React-Projekt zu erstellen und in das Projektverzeichnis zu wechseln, führen Sie die folgenden Befehle aus:
npm create vite@latest react-gantt-firebase -- --template react-ts
cd react-gantt-firebase
Installieren Sie die erforderlichen Abhängigkeiten wie folgt:
npm install firebase
Installation von React Gantt
Installieren Sie React Gantt wie im React Gantt Installationsleitfaden.
In diesem Tutorial verwenden wir das Evaluierungspaket:
npm install @dhtmlx/trial-react-gantt
oder
yarn add @dhtmlx/trial-react-gantt
Wenn Sie bereits das Professional-Paket verwenden, ersetzen Sie @dhtmlx/trial-react-gantt durch @dhx/react-gantt in den Befehlen und Importen.
Schritt 2: Firebase konfigurieren
Erstellen Sie zunächst ein Firebase-Projekt, indem Sie die folgenden Schritte durchführen:
- Gehen Sie zur Firebase Console
- Klicken Sie auf Create a project
- Geben Sie den Projektnamen ein (z. B.
react-gantt-firebase) und folgen Sie den Anweisungen
Dann richten Sie Firestore ein, indem Sie die folgenden Schritte ausführen:
- Navigieren Sie zur Firestore Database im Dashboard Ihres Firebase-Projekts
- Klicken Sie auf Create database
- Wählen Sie Ihren bevorzugten Standort
- Starten Sie im test mode zur leichten Entwicklung (denken Sie daran, die Sicherheitsregeln vor der Produktion zu konfigurieren)
- Klicken Sie auf Create
Registrieren Sie anschließend Ihre Web-App wie folgt:
- Wählen Sie Project Overview in der linken Seitenleiste der Firebase Console
- Klicken Sie auf das Web-App-Symbol
</>, um eine neue Web-App zu registrieren - Geben Sie den App-Spitznamen ein (z. B.
react-gantt-firebase) - Aktivieren Sie Firebase Hosting
- Klicken Sie auf Register app
- Kopieren Sie die generierte Firebase-Konfiguration (Sie verwenden sie in Ihrem Projekt)
Schlussendlich konfigurieren Sie Firebase in Ihrem Projekt wie unten beschrieben:
- Fügen Sie Ihre Firebase-Konfiguration in die Datei
.envwie folgt ein:
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"
}
Ersetzen Sie den Platzhalter YOUR_API_KEY durch Ihre tatsächlichen Firebase-Projektdaten.
- Erstellen Sie eine neue Datei firebase.ts und initialisieren Sie Firebase und Firestore. Exportieren Sie außerdem Referenzen zu Sammlungen, wie unten gezeigt:
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 };
Schritt 3: Erstellung der Gantt-Komponente
Zu Beginn richten Sie die Kern-Gantt-Komponente mit React-State für Tasks und Links mit der folgenden Konfiguration ein:
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,
};
Im obigen Snippet:
- Templates
Templates ermöglichen es uns, zu steuern, wie Daten in der Gantt-Komponente geparst und formatiert werden.
Da Firestore Daten als Strings speichert, müssen wir sie wieder in Date-Objekte konvertieren (parse_date) und korrekt für die Speicherung formatieren (format_date).
- Config
Die auto_scheduling-Option ermöglicht eine automatische Neuberechnung abhängiger Aufgaben, wenn eine übergeordnete Aufgabe verschoben oder geändert wird.
Dies ist nützlich für Szenarien im Projektmanagement.
Erstellen Sie nun State-Handler, um den internen Zustand der Gantt-Komponente wie folgt zu verwalten:
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);
Dies bietet eine einheitliche Methode, den lokalen Zustand zu aktualisieren, wenn Firebase-Daten sich ändern.
Da wir mit zwei Entitätstypen arbeiten – Tasks und Links – können wir eine einheitliche Konfigurationsstruktur erstellen, um beide zu handhaben, statt den Code zu duplizieren. Dieses Objekt ordnet jeden Entitätstyp seiner Firestore-Sammlung, dem API-Pfad und den State-Handlern zu. Unten sehen Sie den Codeausschnitt:
const entityConfig = {
task: {
collection: tasksCollection,
path: "tasks",
handlers: taskHandlers,
},
link: {
collection: linksCollection,
path: "links",
handlers: linkHandlers,
},
};
Projektstruktur-Übersicht
Sie können die Übersicht der resultierenden Projektstruktur in folgendem Scheme prüfen:
src/
├── App.tsx # Einstiegspunkt
├── App.css # Stile
├── components/
│ └── Gantt/
│ ├── Gantt.tsx # Hauptlogik
│ └── types.ts # Typdeklarationen
├── config/
│ └── firebase.ts # Firebase-Setup
└── main.tsx # React-Wurzel
Schritt 4: Laden von Initialdaten
Wenn die Komponente gemountet wird, sollten Sie alle Tasks und Links wie folgt laden:
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();
};
}, []);
Um Firebase-Dokumente in Gantt-kompatible Objekte umzuwandeln, verwenden Sie processEntity wie unten angegeben:
const processEntity = (docSnapshot: QueryDocumentSnapshot): Task | Link => {
return { ...docSnapshot.data(), id: docSnapshot.id };
};
Schritt 5: Echtzeit-Synchronisierung einrichten
Verwenden Sie die Firebase-Funktion onSnapshot, um Änderungen in beiden Sammlungen zu abonnieren und sich abzumelden, wenn die Komponente entmountet wird:
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 };
}
Der erste onSnapshot-Aufruf liefert die anfänglichen Daten, Änderungen werden nicht geliefert. Deshalb ignorieren wir im watchRealtime den ersten Aufruf (da wir bereits die anfänglichen Daten geladen haben).
Verarbeitung von Echtzeit-Updates
Verarbeiten Sie die Echtzeit-Updates mit der Funktion aus dem folgenden Code-Beispiel:
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);
});
}
Diese Methode stellt sicher, dass nur serverbestätigte Änderungen verarbeitet werden und so lokale Duplikationen vermieden werden.
docChanges() gibt die Liste der Änderungen (added, modified, removed) zurück, die seit dem letzten Snapshot in der Firestore-Sammlung vorgenommen wurden. Firestore liefert den Typ der Änderung (added, modified, removed), und wir leiten ihn an den entsprechenden Handler weiter, um den React-Zustand zu aktualisieren.
Schritt 6: CRUD-Operationen mit Firebase implementieren
Um die Create-/Update-/Delete-Anfragen der Gantt-Komponente zu verarbeiten, verwenden Sie die Logik der data.save-Methode, die unten angegeben ist:
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 wird diese Änderungen automatisch an alle verbundenen Clients über die Snapshot-Listener weitergeben.
Dann rendern Sie das Gantt-Diagramm mit folgendem Code:
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
<ReactGantt
tasks={tasks}
links={links}
templates={templates}
config={config}
data={data}
/>
</div>
);
Die data-Eigenschaft verbindet die integrierte Bearbeitung von Gantt mit der oben bereitgestellten Firebase-save-Logik.
Schritt 7: Bereitstellung des Projekts für Firebase
Sobald Ihr Projekt vollständig funktioniert und die Echtzeit-Synchronisierung korrekt läuft, können Sie es bereitstellen, damit es öffentlich im Web zugänglich ist. Es gibt zwei Deploy-Optionen: über die Firebase CLI und über die Firebase Console.
Bereitstellung über die Firebase CLI (Empfohlen)
Dies ist die effizienteste Methode, insbesondere wenn Sie Ihr Projekt regelmäßig aktualisieren möchten. Folgen Sie den untenstehenden Schritten:
1. Wenn Sie die Firebase CLI noch nicht installiert haben, installieren Sie sie mit folgendem Befehl:
npm install -g firebase-tools
2. Melden Sie sich bei Firebase an, mit dem folgenden Befehl:
firebase login
3. Initialisieren Sie Firebase in Ihrem Projekt mit folgendem Befehl:
firebase init
Während der Initialisierung führen Sie die untenstehenden Schritte aus:
- Hosting auswählen (Sie können auch Firestore auswählen, falls Sie es noch nicht konfiguriert haben)
- Legen Sie den Build-Ordner fest (z. B.
distoderbuild, abhängig von Ihrervite.config.tsoderpackage.json-Config) - Wenn Sie gefragt werden, ob es sich um eine Single Page App (SPA) handelt, wählen Sie Yes, damit alle Routen über
index.htmlbedient werden
4. Bauen Sie das Projekt nun mit folgendem Befehl:
npm run build
Es generiert die produktionsbereiten Dateien im Ordner dist (oder build).
5. Schließlich können Sie über folgenden Befehl zu Firebase deployen:
firebase deploy
Nach Abschluss der Bereitstellung stellt Firebase Ihnen einen Link zu Ihrem gehosteten Projekt bereit.
Schnelle Bereitstellung über die Firebase Console
Wenn Sie die Veröffentlichung ohne CLI schnell durchführen möchten, können Sie dies direkt über die Firebase Console tun. Folgende Schritte sind zu erledigen:
1. Bauen Sie das Projekt mit dem untenstehenden Befehl:
npm run build
2. Gehen Sie zu Firebase Hosting → Ihr Projekt → Hosting
3. Klicken Sie auf "Get Started" oder "Upload"
4. Laden Sie den Inhalt des Ordners dist (oder build) hoch
5. Bestätigen Sie den Upload – Firebase stellt Ihnen eine öffentliche URL für Ihre Seite bereit
Fazit
In diesem Tutorial haben wir ein Echtzeit-Gantt-Diagramm mit Firebase-Synchronisation erstellt. Sie haben gelernt, wie man:
- React Gantt mit Firebase Firestore verbindet
- Echtzeit-Abonnements für Firestore einrichtet
- Erstellen-, Aktualisieren- und Löschen-Ereignisse mit sofortiger Multi-Client-Synchronisation verarbeitet
Dieser Ansatz eignet sich perfekt für kollaborative Projektmanagement-Tools, bei denen alle Nutzer Live-Updates sehen müssen, ohne die Seite neu zu laden.