Add Function Delayed Input Processing Example (#3586)

Co-authored-by: Mattuwu <syan4@ualberta.ca>
Co-authored-by: Kirill <burnytc@gmail.com>
This commit is contained in:
Ruslan S. 2025-08-21 19:23:14 +02:00 committed by GitHub
parent 741849d892
commit 0102d62d60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 137 additions and 0 deletions

9
Cargo.lock generated
View File

@ -871,6 +871,15 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "function_delayed_input"
version = "0.1.0"
dependencies = [
"gloo-timers",
"web-sys",
"yew",
]
[[package]]
name = "function_memory_game"
version = "0.1.0"

View File

@ -41,6 +41,7 @@ As an example, check out the TodoMVC example here: <https://examples.yew.rs/todo
| [counter_functional](counter_functional) | [F] | Simple counter which can be incremented and decremented made using function components. |
| [dyn_create_destroy_apps](dyn_create_destroy_apps) | [S] | Uses the function `Renderer::with_root_and_props` and the `AppHandle` struct to dynamically create and delete Yew apps. |
| [file_upload](file_upload) | [S] | Uses [`gloo::file`](https://docs.rs/gloo-file/latest/gloo_file/index.html) to read the content of user uploaded files. |
| [function_delayed_input](function_delayed_input) | [F] | Demonstrates how to implement a form with delayed input processing. |
| [function_memory_game](function_memory_game) | [F] | Implementation of [Memory Game](https://github.com/bradlygreen/Memory-Game). |
| [function_router](function_router) | [F] | Identical to [`router`](router) but using function components. |
| [function_todomvc](function_todomvc) | [F] | Implementation of [TodoMVC](http://todomvc.com/) using function components and hooks. |

View File

@ -0,0 +1,11 @@
[package]
name = "function_delayed_input"
version = "0.1.0"
authors = ["Ruslan Sibgatullin <info@pudding.pro>"]
edition = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
gloo-timers = { version = "0.3.0", features = ["futures"] }
web-sys = { version = "0.3.67", features = ["Window"]}
yew = { path = "../../packages/yew", features = ["csr"] }

View File

@ -0,0 +1,18 @@
# Delayed Input Processing Example
[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_delayed_input)](https://examples.yew.rs/function_delayed_input)
This is a demonstration of how to create an input form with delayed input processing.
A typical use case is to send user input to the backend only when they have stopped typing, rather than on every keystroke.
## Concepts
- Uses [`gloo-timers`](https://crates.io/crates/gloo-timers) to delay the processing
## Running
Run this application with the trunk development server:
```bash
trunk serve --open
```

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Yew • Function Delayed Input</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link data-trunk rel="rust"/>
</head>
<body></body>
</html>

View File

@ -0,0 +1,86 @@
use std::time::Duration;
use gloo_timers::callback::Timeout;
use web_sys::wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
use yew::*;
#[component]
fn App() -> Html {
#[derive(PartialEq, Default, Clone)]
enum Search {
#[default]
Idle,
Fetching(AttrValue),
Fetched(AttrValue),
}
let search = use_state(Search::default);
use_effect_with(search.clone(), {
move |search| {
// here you would typically do a REST call to send the search input to backend
// for simplicity sake here we just set back the original input
if let Search::Fetching(query) = &**search {
yew::platform::spawn_local({
let query = query.clone();
let search = search.setter();
async move {
// Simulate a network delay
gloo_timers::future::sleep(Duration::from_millis(500)).await;
search.set(Search::Fetched(
format!("Placeholder response for: {}", query).into(),
));
}
});
}
}
});
let oninput = {
let timeout_ref = use_mut_ref(|| None);
use_callback((), {
let search = search.clone();
move |e: InputEvent, _| {
if let Some(target) = e.target() {
let input = target.dyn_into::<HtmlInputElement>().ok();
if let Some(input) = input {
let value = input.value();
if !value.is_empty() {
let search = search.setter();
let timeout = Timeout::new(1_000, move || {
search.set(Search::Fetching(value.into()));
});
(*timeout_ref.borrow_mut()) = Some(timeout);
}
}
}
}
})
};
html! {
<div class="container p-2">
<div class="row">
<div class="p-2">
<form class="input-group bg-dark border border-white rounded">
<input id="search" autocomplete="off" type="search" class="form-control" placeholder="Type something here..." aria-label="Search" {oninput}/>
</form>
</div>
<div class="p-2 border border-black rounded">
<p>{
match &*search {
Search::Idle => "Type something to search...".into(),
Search::Fetching(query) => format!("Searching for: {}", query).into(),
Search::Fetched(response) => response.clone(),
}
}</p>
</div>
</div>
</div>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}