Kurs Svelte i SvelteKit · Moduł 3: Reaktywność i runy
$derived - Wartości pochodne
W tej lekcji5
$derived tworzy wartość, która automatycznie aktualizuje się gdy zmieniają się jej zależności. To jak runa, która reaguje na inne runy!
Podstawowe użycie
<script>
let warriors = $state(10);
let ships = $state(2);
// Automatycznie się aktualizuje
let totalPower = $derived(warriors * 10 + ships * 50);
let armyStatus = $derived(
totalPower > 200 ? 'Potężna armia!' : 'Potrzeba więcej wojowników'
);
</script>
<p>Wojownicy: {warriors}, Statki: {ships}</p>
<p>Siła: {totalPower}</p>
<p>Status: {armyStatus}</p>$derived vs $state
<script>
let a = $state(5);
let b = $state(3);
// NIE rób tego - ręczna synchronizacja
let sumWrong = $state(a + b);
// sumWrong nie zaktualizuje się gdy zmieni się a lub b!
// Użyj $derived
let sumRight = $derived(a + b);
// sumRight zawsze będzie aktualne!
</script>Złożone obliczenia
<script>
let items = $state([
{ name: 'Miecz', value: 100, count: 2 },
{ name: 'Tarcza', value: 50, count: 5 },
{ name: 'Hełm', value: 75, count: 3 }
]);
// Obliczenia na tablicy
let totalItems = $derived(
items.reduce((sum, item) => sum + item.count, 0)
);
let totalValue = $derived(
items.reduce((sum, item) => sum + item.value * item.count, 0)
);
let mostValuable = $derived(
items.reduce((max, item) =>
item.value > max.value ? item : max
)
);
</script>
<p>Przedmioty: {totalItems}</p>
<p>Wartość: {totalValue} złota</p>
<p>Najcenniejszy: {mostValuable.name}</p>$derived.by - Złożona logika
Dla bardziej złożonych obliczeń użyj $derived.by:
<script>
let warriors = $state([
{ name: 'Ragnar', strength: 95, isAlive: true },
{ name: 'Bjorn', strength: 88, isAlive: true },
{ name: 'Ivar', strength: 70, isAlive: false }
]);
// Złożona logika z wieloma krokami
let battleReport = $derived.by(() => {
const alive = warriors.filter(w => w.isAlive);
const totalStrength = alive.reduce((sum, w) => sum + w.strength, 0);
const avgStrength = alive.length > 0
? totalStrength / alive.length
: 0;
return {
aliveCount: alive.length,
totalStrength,
avgStrength: Math.round(avgStrength),
strongest: alive.sort((a, b) => b.strength - a.strength)[0]?.name ?? 'Brak'
};
});
</script>
<div class="report">
<h3>Raport bojowy</h3>
<p>Żywych: {battleReport.aliveCount}</p>
<p>Łączna siła: {battleReport.totalStrength}</p>
<p>Średnia siła: {battleReport.avgStrength}</p>
<p>Najsilniejszy: {battleReport.strongest}</p>
</div>Łańcuch derived
<script>
let baseValue = $state(10);
// Każdy derived zależy od poprzedniego
let doubled = $derived(baseValue * 2); // 20
let withBonus = $derived(doubled + 5); // 25
let final = $derived(withBonus * 1.1); // 27.5
</script>Wartości pochodne tworzą łańcuch magii run!
Kod do tej lekcji: App.svelte
<script>
// $derived - derived values
let items = $state([
{ name: 'Sword', value: 100, count: 2 },
{ name: 'Shield', value: 50, count: 5 },
{ name: 'Helmet', value: 75, count: 3 }
]);
// Simple derived
let totalItems = $derived(
items.reduce((sum, i) => sum + i.count, 0)
);
let totalValue = $derived(
items.reduce((sum, i) => sum + i.value * i.count, 0)
);
// $derived.by for complex logic
let report = $derived.by(() => {
const total = items.reduce((sum, i) => sum + i.count, 0);
const value = items.reduce((sum, i) => sum + i.value * i.count, 0);
const mostValuable = items.reduce((max, i) =>
i.value > max.value ? i : max
);
return {
total,
value,
average: total > 0 ? Math.round(value / total) : 0,
mostValuable: mostValuable.name
};
});
function addItem() {
items.push({ name: 'Axe', value: 80, count: 1 });
}
</script>
<main class="treasury">
<h1>Treasury</h1>
<section>
<h2>Items</h2>
<table>
<thead>
<tr>
<th>Item</th>
<th>Value</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{#each items as item}
<tr>
<td>{item.name}</td>
<td>{item.value}</td>
<td>{item.count}</td>
<td>{item.value * item.count}</td>
</tr>
{/each}
</tbody>
</table>
<button onclick={addItem}>+ Add Axe</button>
</section>
<section class="summary">
<h2>Summary ($derived)</h2>
<div class="stats">
<div class="stat">
<span class="label">Items</span>
<span class="value">{totalItems}</span>
</div>
<div class="stat">
<span class="label">Value</span>
<span class="value">{totalValue}</span>
</div>
</div>
</section>
<section class="report">
<h2>Report ($derived.by)</h2>
<p>Total: <strong>{report.total}</strong> items</p>
<p>Value: <strong>{report.value}</strong></p>
<p>Average: <strong>{report.average}</strong>/pc</p>
<p>Most valuable: <strong>{report.mostValuable}</strong></p>
</section>
</main>
<style>
.treasury {
font-family: 'Georgia', serif;
max-width: 600px;
margin: 0 auto;
padding: 2rem;
background: #1a0f0a;
color: #e8d5b7;
}
h1, h2 {
color: #d4af37;
}
section {
background: rgba(212, 175, 55, 0.1);
border: 1px solid #d4af37;
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1rem;
}
th, td {
padding: 0.5rem;
text-align: left;
border-bottom: 1px solid #3d2914;
}
th {
color: #d4af37;
}
button {
padding: 0.5rem 1rem;
background: #3d2914;
color: #e8d5b7;
border: 1px solid #d4af37;
border-radius: 4px;
cursor: pointer;
}
.stats {
display: flex;
gap: 2rem;
}
.stat {
text-align: center;
}
.stat .label {
display: block;
color: #8b7355;
font-size: 0.9rem;
}
.stat .value {
font-size: 1.5rem;
color: #d4af37;
}
strong {
color: #d4af37;
}
</style>Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Do czego służy $derived?
2. Kiedy użyć $derived.by zamiast $derived?
Zadania praktyczne w grze
- Edytor kodu
Uzupełnij kod, aby doubled było podwojoną wartością count