React per il Terminale in Rust con Flexbox e Hooks
Se hai mai scritto un'interfaccia console in Rust, probabilmente hai usato Ratatui. È una libreria solida che alimenta decine di ottime utility. Ma una volta che un progetto va oltre un paio di pulsanti, inizia la solita routine: devi dividere manualmente lo schermo in rettangoli usando Layout, calcolare percentuali e margini, e passare eventi attraverso costrutti match massicci. Nello sviluppo web, siamo da tempo abituati all'approccio a componenti e a flexbox, ma nel terminale scriviamo ancora spesso come se fosse il 1998.
Ho scoperto di recente la crate iocraft, il cui autore ha risolto questo problema in modo radicale. Ha portato l'esperienza di React, SwiftUI e Ink direttamente nel mondo della programmazione di sistema in Rust.
Un Modello a Componenti Familiare
La libreria è costruita attorno alla macro element!. Costruisce un albero di elementi usando una sintassi che ricorda fortemente JSX o Swift dichiarativo. Nessun calcolo manuale delle coordinate. Il layout è gestito dal motore taffy, che implementa fedelmente la specifica flexbox per Rust.
Ecco come appare un classico Hello World:
use iocraft::prelude::*;
fn main() {
element! {
View(
border_style: BorderStyle::Round,
border_color: Color::Blue,
) {
Text(content: "Hello, world!")
}
}
.print();
}
Semplicemente avvolgiamo Text in un contenitore View, applichiamo un bordo blu arrotondato e chiamiamo .print(). Il risultato va in standard output senza bisogno di catturare il terminale in modalità schermo intero. Questo è comodo se hai bisogno di output di comandi console o log formattati in modo ordinato, piuttosto che di una dashboard interattiva.
Hooks e Stato Dentro il Terminale
La somiglianza con lo sviluppo frontend non finisce con il layout statico. Per le interfacce dinamiche, l'autore ha aggiunto la macro #[component] e familiari lifecycle hooks.
Nel codice qui sotto, il componente Counter mantiene il proprio stato locale tramite use_state e avvia un timer async in background tramite use_future:
use iocraft::prelude::*;
use std::time::Duration;
#[component]
fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
let mut count = hooks.use_state(|| 0);
hooks.use_future(async move {
loop {
smol::Timer::after(Duration::from_millis(100)).await;
count += 1;
}
});
element! {
Text(color: Color::Blue, content: format!("counter: {}", count))
}
}
fn main() {
smol::block_on(element!(Counter).render_loop()).unwrap();
}
Quando il valore count cambia, iocraft triggera un ridisegno della parte interessata dello schermo. Il motore ottimizza il passaggio delle props: contesto e parametri vengono passati per riferimento, quindi non ci sono allocazioni di memoria non necessarie o clonazioni di strutture pesanti qui.
Cosa Sa Fare la Libreria in Pratica
Le primitive integrate sono sufficienti per costruire interfacce di qualsiasi complessità. Gli esempi nel repository contengono ricette pronte per i compiti più comuni:
- Applicazioni a schermo intero con input di testo e gestione del focus
- Tabelle adattive multi-colonna
- Moduli interattivi con validazione
- Calcolatrici e overlay con finestre modali flottanti
Vediamo come appaiono in pratica i layout di elementi complessi:
Lo styling è multipiattaforma. Le applicazioni vengono renderizzate correttamente sia nei terminali standard Linux/macOS che in Windows PowerShell.
Vale la Pena Passare da Ratatui
Se hai già un client terminale complesso scritto in Ratatui, non ha molto senso riscriverlo da zero. Ratatui è più maturo, con una grande community e decine di widget di terze parti scritti per esso.
Ma se stai iniziando una nuova utility CLI, scrivendo uno strumento interno per il tuo team, o sei semplicemente stanco di contare manualmente righe e colonne del terminale, iocraft fa risparmiare molto tempo. La sintassi dichiarativa rende il codice più compatto, e flexbox elimina il mal di testa del ridimensionamento delle finestre.
Il progetto è distribuito con licenza duale MIT / Apache-2.0. La documentazione su docs.rs è sufficientemente dettagliata, e il codice sorgente degli esempi nel repository mostra chiaramente come costruire i propri componenti.
Progetti correlati