System komponentów Astro

Komponenty .astro to podstawowy budulec aplikacji. Łączą znajomą składnię HTML z możliwościami JavaScript wykonywanego na serwerze.

Anatomia komponentu

---
// 1. FRONTMATTER — TypeScript/JavaScript, wykonywany na serwerze
interface Props {
  title: string;
  count?: number;
}

const { title, count = 0 } = Astro.props;
const doubled = count * 2;
---

<!-- 2. SZABLON — HTML z wyrażeniami -->
<div class="card">
  <h2>{title}</h2>
  <p>Podwojona wartość: {doubled}</p>
</div>

<!-- 3. STYLE — automatycznie scopowane -->
<style>
  .card { border-radius: 8px; }  /* nie wpłynie na inne .card w projekcie */
</style>

Props z TypeScript

Deklaracja interface Props pozwala na pełne typowanie:

---
interface Props {
  variant: 'primary' | 'secondary';
  disabled?: boolean;
  onClick?: () => void;
}

const { variant, disabled = false } = Astro.props;
---

<button class={`btn btn-${variant}`} disabled={disabled}>
  <slot />
</button>

Sloty — przekazywanie treści

<slot /> to miejsce, gdzie zostanie wstawiona zawartość przekazana do komponentu:

<!-- Definicja w Card.astro -->
<div class="card">
  <slot name="header" />   <!-- named slot -->
  <div class="body">
    <slot />               <!-- domyślny slot -->
  </div>
  <slot name="footer" />   <!-- named slot -->
</div>
<!-- Użycie w innej stronie -->
<Card>
  <h2 slot="header">Tytuł karty</h2>
  <p>Treść trafia do domyślnego slotu.</p>
  <a slot="footer" href="/more">Więcej →</a>
</Card>

Integracje z innymi frameworkami

Astro obsługuje komponenty React, Vue, Svelte i inne przez integracje:

npx astro add react
npx astro add vue
npx astro add svelte

Bez dyrektywy client:* komponenty są renderowane tylko na serwerze (zero JS):

---
import ReactCounter from './ReactCounter.tsx';
import VueWidget from './Widget.vue';
---

<!-- Statyczny HTML, zero hydratacji -->
<ReactCounter />

<!-- Hydratacja po załadowaniu, tylko gdy potrzebna -->
<VueWidget client:visible />

To jest serce Islands Architecture — interaktywność tylko tam, gdzie naprawdę potrzeba.


← Wróć do bloga