Listen rendern
Lerne, wie du Arrays von Daten in React als Listen renderst. Verstehe das key-Attribut und verschiedene Rendering-Patterns.
Listen rendern
In fast jeder App musst du Listen von Daten anzeigen – Produkte, Benutzer, Nachrichten oder Todos. React macht das mit der map()-Methode aus JavaScript elegant und einfach.
Grundlagen: Arrays mit map() rendern
Die map()-Methode verwandelt jedes Element eines Arrays in ein JSX-Element:
function FruitList() {
const fruits = ['Apfel', 'Banane', 'Kirsche', 'Dattel', 'Erdbeere'];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
Wie es funktioniert
// 1. Du hast ein Array
const fruits = ['Apfel', 'Banane', 'Kirsche'];
// 2. map() verwandelt jedes Element
fruits.map((fruit, index) => <li key={index}>{fruit}</li>);
// 3. Das Ergebnis ist ein Array von JSX-Elementen:
// [<li>Apfel</li>, <li>Banane</li>, <li>Kirsche</li>]
// 4. React rendert dieses Array automatisch
Das key-Attribut
Jedes Element in einer Liste braucht ein eindeutiges key-Attribut. React nutzt Keys, um Elemente effizient zu aktualisieren.
Warum Keys wichtig sind
// SCHLECHT - Index als Key (nur als Notloesung)
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
// GUT - Eindeutige ID als Key
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
Regeln fuer Keys
| Regel | Beispiel |
|---|---|
| Eindeutig unter Geschwistern | Keine doppelten Keys in derselben Liste |
| Stabil | Aendert sich nicht zwischen Renders |
| Nicht Index (wenn moeglich) | IDs aus der Datenbank verwenden |
// Datenbank-IDs sind ideal
const users = [
{ id: 'u1', name: 'Max' },
{ id: 'u2', name: 'Anna' },
{ id: 'u3', name: 'Tom' }
];
function UserList() {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Wann Index als Key okay ist
Der Index als Key ist akzeptabel, wenn:
- Die Liste sich nie aendert (kein Sortieren, Filtern, Loeschen)
- Die Elemente keinen eigenen State haben
- Die Liste nicht neu sortiert wird
Objekt-Arrays rendern
In der Praxis arbeitest du meistens mit Arrays von Objekten:
function ProductList() {
const products = [
{ id: 1, name: 'Laptop', price: 999.99, inStock: true },
{ id: 2, name: 'Maus', price: 29.99, inStock: true },
{ id: 3, name: 'Tastatur', price: 79.99, inStock: false },
{ id: 4, name: 'Monitor', price: 449.99, inStock: true }
];
return (
<div>
<h2>Unsere Produkte</h2>
{products.map(product => (
<div key={product.id} style={{
padding: '1rem',
borderBottom: '1px solid #eee',
opacity: product.inStock ? 1 : 0.5
}}>
<h3>{product.name}</h3>
<p>{product.price.toFixed(2)} Euro</p>
<span>{product.inStock ? 'Verfuegbar' : 'Ausverkauft'}</span>
</div>
))}
</div>
);
}
Listen mit Komponenten
Lagere die Listenelemente in eigene Komponenten aus:
function TodoItem({ todo, onToggle }) {
return (
<div style={{
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
padding: '0.5rem',
borderBottom: '1px solid #eee'
}}>
<input
type="checkbox"
checked={todo.done}
onChange={() => onToggle(todo.id)}
/>
<span style={{
textDecoration: todo.done ? 'line-through' : 'none',
color: todo.done ? '#999' : '#333'
}}>
{todo.text}
</span>
</div>
);
}
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'React lernen', done: false },
{ id: 2, text: 'Projekt bauen', done: false },
{ id: 3, text: 'Deployen', done: false }
]);
function handleToggle(id) {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
));
}
return (
<div>
<h2>Meine Todos</h2>
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} onToggle={handleToggle} />
))}
</div>
);
}
Listen filtern
Kombiniere filter() mit map():
function FilteredUserList() {
const users = [
{ id: 1, name: 'Max', role: 'admin', active: true },
{ id: 2, name: 'Anna', role: 'user', active: true },
{ id: 3, name: 'Tom', role: 'user', active: false },
{ id: 4, name: 'Lisa', role: 'admin', active: true }
];
const [filter, setFilter] = useState('all');
const filteredUsers = users.filter(user => {
if (filter === 'admin') return user.role === 'admin';
if (filter === 'active') return user.active;
return true; // 'all'
});
return (
<div>
<div style={{ marginBottom: '1rem' }}>
<button onClick={() => setFilter('all')}>Alle</button>
<button onClick={() => setFilter('admin')}>Admins</button>
<button onClick={() => setFilter('active')}>Aktive</button>
</div>
{filteredUsers.length > 0 ? (
<ul>
{filteredUsers.map(user => (
<li key={user.id}>
{user.name} ({user.role})
{!user.active && ' - Inaktiv'}
</li>
))}
</ul>
) : (
<p>Keine Benutzer gefunden.</p>
)}
<p>{filteredUsers.length} Ergebnis(se)</p>
</div>
);
}
Listen sortieren
function SortableList() {
const [sortBy, setSortBy] = useState('name');
const [sortOrder, setSortOrder] = useState('asc');
const items = [
{ id: 1, name: 'Banane', price: 1.29 },
{ id: 2, name: 'Apfel', price: 0.99 },
{ id: 3, name: 'Kirsche', price: 3.49 },
{ id: 4, name: 'Dattel', price: 5.99 }
];
const sortedItems = [...items].sort((a, b) => {
let comparison = 0;
if (sortBy === 'name') {
comparison = a.name.localeCompare(b.name);
} else {
comparison = a.price - b.price;
}
return sortOrder === 'asc' ? comparison : -comparison;
});
return (
<div>
<div>
<button onClick={() => setSortBy('name')}>Nach Name</button>
<button onClick={() => setSortBy('price')}>Nach Preis</button>
<button onClick={() => setSortOrder(o => o === 'asc' ? 'desc' : 'asc')}>
{sortOrder === 'asc' ? 'Aufsteigend' : 'Absteigend'}
</button>
</div>
<ul>
{sortedItems.map(item => (
<li key={item.id}>
{item.name} - {item.price.toFixed(2)} Euro
</li>
))}
</ul>
</div>
);
}
Leere Listen behandeln
Zeige immer einen sinnvollen Zustand, wenn die Liste leer ist:
function MessageList({ messages }) {
if (messages.length === 0) {
return (
<div style={{ textAlign: 'center', padding: '2rem', color: '#999' }}>
<p>Keine Nachrichten vorhanden.</p>
<p>Schreibe deine erste Nachricht!</p>
</div>
);
}
return (
<div>
{messages.map(msg => (
<div key={msg.id} style={{ padding: '0.5rem', borderBottom: '1px solid #eee' }}>
<strong>{msg.author}:</strong> {msg.text}
</div>
))}
</div>
);
}
Verschachtelte Listen
function CategoryList() {
const categories = [
{
id: 'c1',
name: 'Frontend',
technologies: ['React', 'Vue', 'Angular', 'Svelte']
},
{
id: 'c2',
name: 'Backend',
technologies: ['Node.js', 'Python', 'Java', 'Go']
},
{
id: 'c3',
name: 'Datenbank',
technologies: ['PostgreSQL', 'MongoDB', 'Redis']
}
];
return (
<div>
{categories.map(category => (
<div key={category.id} style={{ marginBottom: '1rem' }}>
<h3>{category.name}</h3>
<ul>
{category.technologies.map(tech => (
<li key={tech}>{tech}</li>
))}
</ul>
</div>
))}
</div>
);
}
Uebungen
- Rendere eine Kontaktliste mit Name, E-Mail und Telefonnummer aus einem Array von Objekten
- Baue eine filterbare Filmliste mit Genres als Filterbuttons
- Erstelle eine sortierbare Tabelle mit Spalten fuer Name, Alter und Stadt
Was kommt als Naechstes?
Du kannst jetzt Listen in React rendern. Im naechsten Kapitel lernst du den useState Hook kennen – damit kannst du interaktiven State in deinen Komponenten verwalten und deine App wirklich dynamisch machen.
Zusammenfassung
- Nutze
map()um Arrays in JSX-Elemente umzuwandeln - Jedes Listenelement braucht ein eindeutiges
key-Attribut - Verwende Datenbank-IDs als Keys, nicht den Array-Index
- Kombiniere
filter()undsort()mitmap()fuer dynamische Listen - Behandle immer den leeren Zustand einer Liste
- Lagere Listenelemente in eigene Komponenten aus
Pro-Tipp: Erstelle nie den Key waehrend des Renderns mit Math.random() oder Date.now() – das erzeugt bei jedem Render neue Keys und zerstoert die Performance-Vorteile. Keys muessen stabil und vorhersagbar sein!