Un guide étape par étape
Redux est une bibliothèque de gestion d’état populaire pour les applications JavaScript. Il permet aux développeurs de gérer l’état de leurs applications de manière prévisible et cohérente, ce qui facilite le développement et la maintenance d’applications complexes.
Dans cet article de blog, nous explorerons comment implémenter Redux dans Rust, un langage de programmation de systèmes à typage statique connu pour ses performances et sa sécurité.
Pour implémenter Redux dans Rust, nous devrons créer une structure qui représente l’état de notre application et un trait qui définit les actions qui peuvent être effectuées sur l’état. Nous devrons également créer une fonction de réduction qui prend en compte l’état actuel et une action et renvoie un nouvel état basé sur l’action.
Voici un exemple de structure simple qui représente l’état d’une application de tâches :
struct TodoState {
todos: Vec<String>,
}
Ensuite, nous définirons les actions pouvant être effectuées sur l’état à l’aide d’un trait :
trait TodoAction {
fn apply(&self, state: &mut TodoState);
}
Nous pouvons alors définir la fonction de réduction, qui prend l’état actuel et une action, et renvoie un nouvel état basé sur l’action
fn todo_reducer(state: &TodoState, action: &dyn TodoAction) -> TodoState {
let mut new_state = state.clone();
action.apply(&mut new_state);
new_state
}
Maintenant que nous avons la structure de base de notre implémentation Redux en place, nous pouvons définir les actions spécifiques qui peuvent être effectuées sur notre état de choses à faire. Par exemple, nous pourrions avoir une action pour ajouter une nouvelle tâche :
struct AddTodoAction {
todo: String,
}impl TodoAction for AddTodoAction {
fn apply(&self, state: &mut TodoState) {
state.todos.push(self.todo.clone());
}
}
Nous pouvons également définir une action pour supprimer une tâche :
struct RemoveTodoAction {
index: usize,
}impl TodoAction for RemoveTodoAction {
fn apply(&self, state: &mut TodoState) {
state.todos.remove(self.index);
}
}
Avec ces actions en place, nous pouvons maintenant utiliser notre fonction de réduction pour mettre à jour l’état de notre application de tâches en fonction des interactions des utilisateurs. Par exemple, si un utilisateur ajoute une nouvelle tâche, nous pouvons utiliser le todo_reducer
fonction pour mettre à jour l’état comme suit :
let mut state = TodoState { todos: vec![] };
let action = AddTodoAction { todo: "Learn Rust".to_string() };
state = todo_reducer(&state, &action);
Ceci est un exemple très simple d’implémentation de Redux dans Rust, mais il devrait vous donner une bonne idée de la structure de base et de la manière de créer des actions et une fonction de réduction. Il existe de nombreuses autres façons d’implémenter Redux dans Rust, notamment en utilisant une macro pour générer la fonction de réduction et des énumérations pour représenter les actions.
Tout d’abord, nous allons définir une énumération qui représente les différentes actions pouvant être effectuées sur l’état :
enum TodoAction {
AddTodo(String),
RemoveTodo(usize),
}
Ensuite, nous définirons la macro qui générera pour nous la fonction reducer :
#[macro_export]
macro_rules! create_reducer {
($state_type:ty, $action_type:ty, $reducer_fn:expr) => {
fn reducer(state: &$state_type, action: $action_type) -> $state_type {
let mut new_state = state.clone();
$reducer_fn(&mut new_state, action);
new_state
}
}
}
Maintenant, nous pouvons utiliser le create_reducer
macro pour définir notre fonction de réduction comme suit :
create_reducer!(TodoState, TodoAction, |state: &mut TodoState, action| {
match action {
TodoAction::AddTodo(todo) => state.todos.push(todo),
TodoAction::RemoveTodo(index) => state.todos.remove(index),
}
});
Cela générera une fonction de réduction qui prend en compte un TodoState
et un TodoAction
enum et met à jour l’état en fonction de l’action.
Nous pouvons maintenant utiliser la fonction reducer pour mettre à jour l’état de notre application de tâches comme suit :
let mut state = TodoState { todos: vec![] };
let action = TodoAction::AddTodo("Learn Rust".to_string());
state = reducer(&state, action);
Tout d’abord, nous allons définir un composant qui représente un seul élément de tâche :
use yew::{html, Callback, Html};struct TodoItem {
todo: String,
on_remove: Callback<()>,
}
impl Component for TodoItem {
type Message = ();
type Properties = Self;
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
Self {
todo: props.todo,
on_remove: props.on_remove,
}
}
fn update(&mut self, _: Self::Message) -> ShouldRender {
false
}
fn view(&self) -> Html {
html! {
<div>
<span>{ &self.todo }</span>
<button onclick=self.on_remove.clone()>{"Remove"}</button>
</div>
}
}
}
Ensuite, nous définirons le composant principal de notre application, qui contiendra une liste de tâches et un formulaire pour ajouter de nouvelles tâches :
use yew::{html, Callback, Component, ComponentLink, Html, ShouldRender};
use yew_functional::{use_state, use_reducer};struct TodoApp {
link: ComponentLink<Self>,
state: TodoState,
dispatch: Callback<TodoAction>,
}
impl Component for TodoApp {
type Message = ();
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
let state = TodoState { todos: vec![] };
let (dispatch, _) = use_reducer(link, reducer, state);
Self { link, state, dispatch }
}
fn update(&mut self, _: Self::Message) -> ShouldRender {
false
}
fn view(&self) -> Html {
html! {
<div>
<h1>{"Todo List"}</h1>
<ul>
{ for self.state.todos.iter().enumerate().map(|(index, todo)| {
html! {
<TodoItem
todo=todo.clone()
on_remove=self.link.callback(move |_| {
self.dispatch.emit(TodoAction::RemoveTodo(index))
})
/>
}
}) }
</ul>
<form onsubmit=self.link.callback(|event| {
event.prevent_default();
let input = event.target().unwrap().try_into::<HtmlInputElement>().unwrap();
let todo = input.value();
input.set_value("");
self.dispatch.emit(TodoAction::AddTodo(todo))
})>
<input type="text" />
<button type="submit">{"Add Todo"}</button>
</form>
</div>
}
}
Ce composant affichera une liste d’éléments à faire et un formulaire pour ajouter de nouvelles tâches. L’état de l’application est géré à l’aide du use_reducer
crochet de Yew, qui nous permet d’utiliser la fonction de réduction que nous avons définie précédemment pour mettre à jour l’état en fonction des interactions de l’utilisateur.
Pour utiliser ce composant dans une application Yew, vous pouvez l’ajouter au composant racine comme ceci :
use yew::{html, App};fn main() {
yew::initialize();
App::<TodoApp>::new().mount_to_body();
yew::run_loop();
}
Cet exemple vous aide à comprendre comment utiliser Yew et Redux pour créer une application Web dans Rust. Si vous avez des questions ou des suggestions, n’hésitez pas à demander!