Créez une mini liste de tâches
Réunissez tous les acquis dans un petit logiciel de bureau avec saisie, validation, état vide et interrupteurs qui réagissent immédiatement.
Résultat : vous pouvez saisir une tâche, refuser un brouillon vide, ajouter une ligne et basculer son état d'achèvement.
01
Quatre ingrédients, une boucle utile
Chaque ingrédient est déjà apparu seul. Ce chapitre les laisse simplement coopérer.
Saisie du brouillon
TextInput se lie directement à State<String>. Le reducer peut ainsi lire le brouillon actuel quand Add est émis.
Validation bienveillante
Un brouillon vide ou composé uniquement d'espaces produit un message visible sans toucher à la liste.
Lignes dynamiques
La fonction qui construit le contenu lit le vecteur de tâches et crée une carte par élément, ou une carte d'état vide très claire.
Achèvement typé
Chaque Switch émet SetDone avec l'index de sa ligne et la valeur booléenne proposée.
02
Construisez l'application une pièce après l'autre
Assemblez la liste de tâches en quatre petites pièces. Lisez une pièce, lancez l'application, puis passez à la suivante.
Construisez par petites étapes
Chaque bloc de code change une seule idée de l'application de référence vérifiée.
Étape 1 : décrire les données
Task contient des données simples. TaskState regroupe les valeurs réactives et TaskAction liste les intentions permises.
#[derive(Clone)]
struct Task {
title: String,
done: bool,
}
#[derive(Clone)]
enum TaskAction {
Add,
SetDone(usize, bool),
}
#[derive(Clone, Copy)]
struct TaskActions;
impl ActionSchema for TaskActions {
type Action = TaskAction;
}
#[derive(Clone)]
struct TaskState {
draft: State<String>,
tasks: State<Vec<Task>>,
feedback: State<String>,
has_error: State<bool>,
}Étape 2 : valider un ajout
La branche Add lit le brouillon, refuse un titre vide ou ajoute une tâche avant de vider le champ.
TaskAction::Add => {
let title = state.draft.read().trim().to_owned();
if title.is_empty() {
state.feedback.set("Type a task first.".to_owned());
state.has_error.set(true);
} else {
state.tasks.update(|tasks| {
tasks.push(Task { title, done: false });
});
state.draft.set(String::new());
state.feedback.set("Task added. Nice!".to_owned());
state.has_error.set(false);
}
}Étape 3 : afficher une ligne de tâche
Switch est contrôlé ici : il affiche task.done et émet SetDone lorsque l'utilisateur le bascule.
for (index, task) in tasks.into_iter().enumerate() {
list = list.child(
Card::new().padding(theme.spacing().md).child(
Row::new()
.gap(theme.spacing().md)
.align_items(AlignItems::Center)
.child(
Switch::new()
.checked(task.done)
.on_change(move |done| TaskAction::SetDone(index, done)),
)
.child(Text::new(task.title)),
),
);Étape 4 : assembler l'écran
La Column finale réunit la saisie, le retour et la liste sans masquer leurs responsabilités séparées.
.child(
Row::new()
.gap(theme.spacing().md)
.child(
TextInput::new()
.bind(view_state.draft.clone())
.placeholder("Ship a friendly example")
.width(420.0),
)
.child(
Button::with_label("Add task")
.on_click(TaskAction::Add),
),
)
.child(
Text::new(view_state.feedback.clone()).style(TextStyle::new(
FontId::Ui,
14,
feedback_color,
)),
)
.child(task_list(&view_state, theme)),Compilé avec Rust 1.88 sur beta.2. Ces quatre extraits viennent d'une fixture vérifiée qui utilise uniquement le prelude public.
03
Concevez chaque état, pas seulement le chemin idéal
Une petite application paraît déjà complète quand elle explique ce qui se passe avant, pendant et après une action.
Vide
La première carte invite à une action utile au lieu de laisser une zone blanche mystérieuse.
Titre requis
L'envoi d'un brouillon vide affiche une erreur directe et conserve la position de l'utilisateur.
Ajoutée
Un ajout réussi vide le champ, crée une ligne et répond avec un petit message positif.
Basculée
L'interrupteur peut terminer ou rouvrir une tâche, et les deux directions actualisent le message de retour.
04
Vous possédez maintenant de vraies fondations
Vous avez composé une fenêtre native, appliqué les jetons du thème, partagé des valeurs réactives, émis des actions typées, validé une saisie et rendu une liste changeante.
WindowThemeStateActionSchemaTextInputSwitchGardez beta.2 à portée de main
Épinglez la dépendance exacte tant que l'API est en beta et recompilez chaque exemple avant d'adopter une version plus récente.
Un raccourci adapté aux petites listes
Cette version pour débuter identifie les lignes par leur index, tandis que tasks.read() clone tout le Vec<Task>. Cela convient à une petite liste. Lorsque les données grandissent, donnez un identifiant stable à chaque tâche, attachez-le à la ligne avec .key(...) et préférez des mises à jour plus ciblées.
À vous de jouer
Exercice : rangez la liste de tâches
Ajoutez une petite action de nettoyage et un résumé vraiment utile.
- 1Affichez le nombre de tâches inachevées avec un texte dérivé.
- 2Ajoutez ClearCompleted et un bouton qui retire les tâches terminées.
Filtrez le vecteur dans State::update et renvoyez Commands::none une fois la modification terminée.
Le nombre change après chaque bascule et le bouton retire uniquement les tâches terminées.