Errori e fix

Astro: il componente è statico perché manca la client directive

In Astro un componente framework senza `client:*` viene renderizzato in HTML e mai idratato. Il markup c'è, gli eventi no. La direttiva giusta dipende da quando serve l'interattività.

In sintesi

  • Senza `client:*` il componente è HTML statico: nessun evento, nessuno stato.
  • Scegli la direttiva in base al momento: `client:load` subito, `client:idle` dopo, `client:visible` quando entra in viewport.
  • `client:only` richiede il nome del framework e salta del tutto il render sul server.

Risposta breve: senza una direttiva client:*, un componente React, Vue o Svelte dentro Astro viene reso in HTML e mai idratato. Il markup c'è, gli eventi no. Aggiungi la direttiva in base a quando serve l'interattività.

Le direttive

DirettivaQuando idrataUso tipico
client:loadsubitocontrolli sopra la piega
client:idlequando il browser è liberointerazioni secondarie
client:visiblequando entra in viewportsezioni in fondo alla pagina
client:onlysolo nel browsercanvas, editor, API del browser

Perché l'HTML arriva già finito

Il meccanismo è la compilazione. Astro legge il file .astro a build time e chiede al renderer del framework una stringa HTML. La direttiva client:* è ciò che trasforma quella stringa in un elemento astro-island, con l'URL del componente, quello del renderer e le props serializzate negli attributi. Senza direttiva il nodo esce come HTML puro: nessuno script lo raggiunge, quindi nessun listener viene registrato e nessuno stato esiste. Il componente non è rotto, è una fotografia.

L'esempio

---
import Counter from "../components/Counter.tsx";
---








client:only richiede il nome del framework perché Astro non può dedurlo dal file: senza, la build fallisce.

Come verificarlo

# quante isole contiene davvero l'HTML servito
curl -s http://localhost:4321/ | grep -o "<astro-island" | wc -l

# quali direttive esistono nel sorgente
# (PowerShell: Select-String -Path src/**/*.astro -Pattern "client:")
grep -rn "client:" src --include="*.astro"

Il primo comando conta le isole nell'HTML servito, il secondo trova le direttive nel sorgente. Se il conteggio è zero su una pagina che dovrebbe essere interattiva, la causa è nel sorgente. Se è molto più alto di quanto ti aspetti, il problema è l'opposto e costa byte: una tabella con una direttiva per riga diventa una fila di punti di idratazione.

Cosa non passa attraverso un'isola

Le props devono essere serializzabili. Una funzione passata dal file .astro al componente non attraversa il confine: il componente riceve undefined e l'errore arriva a runtime. Passa dati o definisci il gestore dentro il componente client.

Quando la correzione non funziona

Se aggiungi la direttiva e l'evento continua a non funzionare, controlla la console: un errore di idratazione annulla il mount dell'isola. Un secondo caso è un componente che dipende da un contesto React creato fuori dall'isola: ogni isola è un albero separato, e il provider deve stare dentro.

Attenzione anche al costo: ogni isola porta il runtime del framework. Dieci isole React sulla stessa pagina significano un runtime caricato una volta, ma dieci punti di idratazione da coordinare. Preferisci una sola isola che contiene l'interazione.

Quando la correzione tipica peggiora le cose

La correzione che circola è mettere client:load ovunque qualcosa non risponde. Risolve il sintomo e aggiunge due costi. Astro serializza le props dentro l'attributo dell'isola: una lista di quaranta righe con una direttiva per riga produce quaranta isole e quaranta copie dei dati nel documento, che il browser legge e idrata una per una. Il peso dell'HTML cresce, il tempo prima dell'interattività anche, e il problema di partenza era una sola direttiva mancante.

Il limite di client:visible

Un limite noto di client:visible: l'idratazione dipende da IntersectionObserver. Se l'isola sta dentro un pannello chiuso, un contenitore con altezza zero o un elemento con display:none, non interseca mai il viewport e resta inerte. Non compare un errore, il markup è corretto e il comando non risponde: la diagnosi somiglia di nuovo a una direttiva mancante, e la prima ipotesi sbagliata costa mezz'ora.

Come prevenirlo

  • Per default, nessuna direttiva: aggiungila solo dove serve un evento.
  • Preferisci client:visible per le sezioni sotto la piega.
  • Verifica nell'HTML la presenza di astro-island e del chunk del framework.
  • Una sola isola per area interattiva: se servono dieci direttive per dieci righe, il confine è nel posto sbagliato.

Dove continuare

Nel catalogo: blocco hero, componenti e blocchi. Le guide: struttura App Router e checklist accessibilità; il confronto: peso di una libreria UI.

Domande frequenti

Perché il bottone non risponde al click?

Il componente è stato renderizzato in HTML senza idratazione. Aggiungi la direttiva `client:*` appropriata.

`client:load` e `client:idle` cambiano l'aspetto?

No. Cambiano quando il JavaScript viene eseguito; l'HTML iniziale è lo stesso, salvo componenti che dipendono dall'interattività per il primo paint.

Quando serve `client:only`?

Quando il componente non può essere renderizzato sul server: usa il browser, un canvas o una libreria che accede a `window` all'import.

Perché `client:only` richiede un valore?

Perché Astro non può dedurre il framework dal file in quel caso: scrivi `client:only="react"`.

Come verifico che l'isola sia idratata?

Guarda nell'HTML l'attributo `astro-island` e nel pannello Network il chunk del framework. Se manca il chunk, la direttiva non è stata applicata.