Lernzettel
| Vorteile | Nachteile |
|---|---|
| Direkte Hardwarezugriffe | Hohe Entwicklungskosten |
| Hohe Performance | Zwei Codebases -> Hohe Wartungskosten |
| Vollständige Nutzung der Plattform-Features | Längere Entwicklungszeit |
| Vorteile | Nachteile |
|---|---|
| Geringe Entwicklungskosten | Eingeschränkte Performance |
| Ein Codebase für alle Plattformen | Eingeschränkter Zugriff auf Hardware-Features |
| Schnellere Entwicklung | Abhängigkeit von Frameworks |
| Einheitliches UI | App integriert sich nicht in das Systemdesign |
| Vorteile | Nachteile |
|---|---|
| Plattformunabhängig | Eingeschränkter Zugriff auf Hardware-Features |
| Einfache Verteilung | Eingeschränkte Performance & native Funktionen |
| Geringe Entwicklungskosten | Abhängigkeit von Browserkompatibilität |
CA
CP
AP
Vorteile von Loose Coupling:
| Aspekt | Microservices | Monolith |
|---|---|---|
| Entwicklung | Komplexer | Einfacher |
| Deployment | Einzeln | Ganzes System |
| Skalierung | Individuell | Ganzes System |
| Wartbarkeit | Flexibel | Schwerfällig |
Beispiel: IndexedDB, SQLite
| Vorteile | Nachteile |
|---|---|
| Offline-Verfügbarkeit | Eingeschränkte Synchronisation |
| Schneller Zugriff | Eingeschränkte Kapazität |
| Kontrolle über Daten | Datenverlust bei App-Deinstallation |
Beispiel: Cloud-Datenbanken wie Firebase, AWS DynamoDB
| Vorteile | Nachteile |
|---|---|
| Skalierbarkeit | Abhängigkeit von Internetverbindung |
| Zentrale Datenverwaltung (-> multi Device möglich | Datenschutzbedenken |
| Einfache Synchronisation | Kosten |
| Technik | Latenz | Ressourcenverbrauch | Komplexität |
|---|---|---|---|
| Polling | Hoch | Hoch | Niedrig |
| Long Polling | Mittel | Mittel | Mittel |
| WebSockets | Niedrig | Niedrig | Hoch |
| Kriterium | CSR | SSR |
|---|---|---|
| Initial Load | Langsam | Schnell |
| SEO | Herausforderung | Besser |
| Serverlast | Niedrig | Hoch |
| Benutzerinteraktion | Flüssig | Langsam |
| JavaScript-Abhängigkeit | Hoch | Niedrig |
State in Funktionskomponenten:
import React, { useState } from 'react';
function Counter() {
// useState-Hook initialisiert den State 'count' mit dem Wert 0
// setCount ist die Funktion, um den State zu aktualisieren
const [count, setCount] = useState(0);
return (
<div>
{/* Anzeige des aktuellen Zählerwerts */}
<p>Aktueller Zähler: {count}</p>
{/* Button, der den Zählerwert bei jedem Klick um 1 erhöht */}
<button onClick={() => setCount(count + 1)}>Zähler erhöhen</button>
</div>
);
}
State-Updates & Batching:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
// Erster setCount-Aufruf mit dem aktuellen Wert von count (0)
// React plant dieses Update, führt es aber nicht sofort aus
setCount(count + 1);
// Zweiter setCount-Aufruf verwendet immer noch den gleichen aktuellen Wert (0)
// Dieser zweite Aufruf überschreibt den ersten in der Warteschlange
setCount(count + 2);
// Zu diesem Zeitpunkt ist count immer noch 0, da die Updates noch nicht angewendet wurden
// React batcht (gruppiert) diese Updates und führt sie nach dem Event-Handler aus
// Das Endergebnis wird 2 sein (0+2), nicht 3, da beide Updates den gleichen Ausgangswert verwenden
// Um Updates sequentiell zu verarbeiten, würde man eine funktionale Form verwenden:
// setCount(prevCount => prevCount + 1);
// setCount(prevCount => prevCount + 2);
// Das Ergebnis wäre dann 3
};
return (
<div>
<p>Aktueller Zähler: {count}</p>
<button onClick={handleClick}>Zähler erhöhen</button>
</div>
);
}
Komplexe State-Objekte:
import React, { useState } from 'react';
function UserProfile() {
// Initialisiere einen komplexen State mit einem Objekt
// Das Objekt enthält zwei Eigenschaften: name und age
const [user, setUser] = useState({ name: 'Max', age: 25 });
const updateName = (newName) => {
// Verwende die funktionale Form von setState für Zugriff auf vorherigen State
setUser((prevUser) => {
// Wichtig: Erstelle ein neues Objekt mit dem Spread-Operator (...)
// Dies sorgt für Immutability - der vorherige State wird nicht mutiert
// ...prevUser kopiert alle bestehenden Eigenschaften
// name: newName überschreibt nur die name-Eigenschaft
return { ...prevUser, name: newName };
});
// FALSCH wäre: user.name = newName; setUser(user);
// Das würde den originalen State direkt mutieren
};
return (
<div>
{/* Zugriff auf Eigenschaften des State-Objekts mit der Punktnotation */}
<p>Name: {user.name}</p>
<p>Alter: {user.age}</p>
{/* Bei Klick wird updateName aufgerufen und der Name auf 'Anna' gesetzt */}
<button onClick={() => updateName('Anna')}>Namen ändern</button>
</div>
);
}
Klassische Lifecycle-Methoden:
constructor, render, componentDidMountrender, componentDidUpdatecomponentWillUnmountHooks Lifecycle:
useEffect(() => { /* Effekt */ }, [Abhängigkeiten])import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
// useEffect wird nach dem ersten Rendern und bei jeder Aktualisierung ausgeführt
useEffect(() => {
// setInterval startet einen Timer, der alle 1000ms (1 Sekunde) setSeconds aufruft
const interval = setInterval(() => {
setSeconds((prevSeconds) => prevSeconds + 1);
}, 1000);
// Cleanup-Funktion: stoppt den Timer, wenn die Komponente unmontiert wird
return () => clearInterval(interval);
}, []); // Leeres Array bedeutet, dass der Effekt nur einmal beim Mounten ausgeführt wird
return <p>Timer: {seconds} Sekunden</p>;
}
Weitere Hooks:
useLayoutEffect: Synchroner Effekt, wird vor dem Browser-Painting ausgeführtuseMemo: Memoisiert Werte, um unnötige Berechnungen zu vermeidenuseCallback: Memoisiert Funktionen, um unnötige Neudefinitionen zu vermeidenuseRef: Referenz auf DOM-Elemente oder Werte, die nicht neu gerendert werden sollenimport React, { useState, useLayoutEffect, useCallback, useMemo, useRef } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
const inputRef = useRef(null);
// useLayoutEffect wird synchron nach dem Rendern ausgeführt
useLayoutEffect(() => {
// Fokus auf das Eingabefeld setzen
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
// useCallback memoisiert die Funktion, um unnötige Neudefinitionen zu vermeiden
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []);
// useMemo memoisiert den Wert, um unnötige Berechnungen zu vermeiden
const squaredCount = useMemo(() => count * count, [count]);
return (
<div>
<input ref={inputRef} type="text" />
<p>Aktueller Zähler: {count}</p>
<p>Quadrat des Zählers: {squaredCount}</p>
<button onClick={increment}>Zähler erhöhen</button>
</div>
);
}
Rendering-Verhalten:
React.memo: Verhindert unnötige Neurenderings von FunktionskomponentenshouldComponentUpdate: Verhindert unnötige Neurenderings von KlassenkomponentenState & Lifecycle Best Practices:
useState, useReducer| Ansatz | Einfachheit | Performance | Skalierbarkeit | Community |
|---|---|---|---|---|
| Context API | Hoch | Mittel | Niedrig | Mittel |
| Redux | Mittel | Hoch | Hoch | Hoch |
| MobX | Mittel | Hoch | Mittel | Mittel |
| Recoil | Hoch | Hoch | Mittel | Niedrig |
| Zustand | Hoch | Hoch | Mittel | Niedrig |
Best Practices für State Management: