Event Handlers
Event handlers are crucial elements in an interactive application. These functions are invoked in response to certain user events like mouse clicks, keyboard input, or form submissions.
In the final section of this guide, we will introduce interactivity to our application by implementing creation, updating, and deletion of film actions. For this, we will be spawning futures
using cx.spawn
and async move
closures. It is crucial to remember that use_state
values should be cloned before being used in async move
closures.
delete_film Function
This function will be triggered when a user clicks the delete button of a film card. It will send a DELETE
request to our API and subsequently call force_get_films
to refresh the list of films. In the event of a successful operation, a message will be logged to the console. If an error occurs, the error will be logged instead.
#![allow(unused)] fn main() { let delete_film = move |filmId| { let force_get_films = force_get_films.clone(); cx.spawn({ async move { let response = reqwest::Client::new() .delete(&format!("{}/{}", &films_endpoint(), filmId)) .send() .await; match response { Ok(_data) => { log::info!("Film deleted"); force_get_films.set(()); } Err(err) => { log::info!("Error deleting film: {:?}", err); } } } }); }; }
create_or_update_film Function
This function is invoked when the user clicks the create or update button of the film modal. It sends a POST
or PUT
request to our API, followed by a call to force_get_films
to update the list of films. The decision to edit or create a film depends on whether the selected_film
state is Some(film)
or None
.
In case of success, a console message is logged, the selected_film
state is reset, and the modal is hidden. If an error occurs, the error is logged.
#![allow(unused)] fn main() { let create_or_update_film = move |film: Film| { let force_get_films = force_get_films.clone(); let current_selected_film = selected_film.clone(); let is_modal_visible = is_modal_visible.clone(); cx.spawn({ async move { let response = if current_selected_film.get().is_some() { reqwest::Client::new() .put(&films_endpoint()) .json(&film) .send() .await } else { reqwest::Client::new() .post(&films_endpoint()) .json(&film) .send() .await }; match response { Ok(_data) => { log::info!("Film created"); current_selected_film.set(None); is_modal_visible.write().0 = false; force_get_films.set(()); } Err(err) => { log::info!("Error creating film: {:?}", err); } } } }); }; }
Final Adjustments
All the subsequent modifications will be implemented on our App
component.
front/src/main.rs
...
fn App(cx: Scope) -> Element {
...
{
let films = films.clone();
use_effect(cx, force_get_films, |_| async move {
let existing_films = get_films().await;
if existing_films.is_empty() {
films.set(None);
} else {
films.set(Some(existing_films));
}
});
}
+ let delete_film = move |filmId| {
+ let force_get_films = force_get_films.clone();
+ cx.spawn({
+ async move {
+ let response = reqwest::Client::new()
+ .delete(&format!("{}/{}", &films_endpoint(), filmId))
+ .send()
+ .await;
+ match response {
+ Ok(_data) => {
+ log::info!("Film deleted");
+ force_get_films.set(());
+ }
+ Err(err) => {
+ log::info!("Error deleting film: {:?}", err);
+ }
+ }
+ }
+ });
+ };
+ let create_or_update_film = move |film: Film| {
+ let force_get_films = force_get_films.clone();
+ let current_selected_film = selected_film.clone();
+ let is_modal_visible = is_modal_visible.clone();
+ cx.spawn({
+ async move {
+ let response = if current_selected_film.get().is_some() {
+ reqwest::Client::new()
+ .put(&films_endpoint())
+ .json(&film)
+ .send()
+ .await
+ } else {
+ reqwest::Client::new()
+ .post(&films_endpoint())
+ .json(&film)
+ .send()
+ .await
+ };
+ match response {
+ Ok(_data) => {
+ log::info!("Film created");
+ current_selected_film.set(None);
+ is_modal_visible.write().0 = false;
+ force_get_films.set(());
+ }
+ Err(err) => {
+ log::info!("Error creating film: {:?}", err);
+ }
+ }
+ }
+ });
+ };
cx.render(rsx! {
...
section {
class: "md:container md:mx-auto md:py-8 flex-1",
rsx!(
if let Some(films) = films.get() {
ul {
class: "flex flex-row justify-center items-stretch gap-4 flex-wrap",
{films.iter().map(|film| {
rsx!(
FilmCard {
key: "{film.id}",
film: film,
on_edit: move |_| {
selected_film.set(Some(film.clone()));
is_modal_visible.write().0 = true
},
- on_delete: move |_| {}
+ on_delete: move |_| {
+ delete_film(film.id);
+ }
}
)
})}
}
)
}
}
FilmModal {
film: selected_film.get().clone(),
- on_create_or_update: move |new_film| {},
+ on_create_or_update: move |new_film| {
+ create_or_update_film(new_film);
+ },
on_cancel: move |_| {
selected_film.set(None);
is_modal_visible.write().0 = false;
}
}
})
}
Upon successful implementation of the above changes, the application should now have the capability to create, update, and delete films.