I am starting to learn Rust with Yew. I followed the counter example in the documentation and now I am trying to implement an input functionality. I want to show the input value in html. I am able to console.log it but not to render it in the browser.
What am I missing?
This is the code I have so far:
use wasm_bindgen::{JsCast, UnwrapThrowExt};
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[function_component]
fn App() -> Html {
let name = use_state(|| "");
let oninput = Callback::from(move |input_event: InputEvent| {
let name = name.clone();
let target: HtmlInputElement = input_event
.target()
.unwrap_throw()
.dyn_into()
.unwrap_throw();
//web_sys::console::log_1(&target.value().into()); // <- can console the value.
move |_: HtmlInputElement| name.set(&target.value().as_str());
});
html! {
<div>
<input {oninput} />
<p>{"name: "}<h5>{name}</h5></p> // <-- here is the error
</div>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
But I get this error:
error[E0277]: `UseStateHandle<&str>` doesn't implement `std::fmt::Display`
--> src/main.rs:22:29
|
22 | <p>{"name"}<h5>{name}</h5></p>
| ^^^^
| |
| `UseStateHandle<&str>` cannot be formatted with the default formatter
| required by a bound introduced by this call
|
= help: the trait `std::fmt::Display` is not implemented for `UseStateHandle<&str>`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required for `UseStateHandle<&str>` to implement `ToString`
= note: required for `VNode` to implement `From<UseStateHandle<&str>>`
= note: required for `UseStateHandle<&str>` to implement `Into<VNode>`
= note: 2 redundant requirements hidden
= note: required for `UseStateHandle<&str>` to implement `Into<NodeSeq<UseStateHandle<&str>, VNode>>`
I tried to use name.get()
, &name
, name.clone()
and combination of those but I always get an error. Could you explain me why I cannot get the value to show in the browser?
I appreciate any help.
To use the value in the state, you need to dereference it:
<p>{"name: "}<h5>{*name}</h5></p>
However, now you will see another errors:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:23:46
|
16 | let name = name.clone();
| ---- lifetime `'1` appears in the type of `name`
...
23 | move |_: HtmlInputElement| name.set(&target.value().as_str());
| ----------^^^^^^^^^^^^^^----------
| | | |
| | | temporary value is freed at the end of this statement
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'1`
error[E0382]: borrow of moved value: `name`
--> src/main.rs:29:31
|
14 | let name = use_state(|| "");
| ---- move occurs because `name` has type `UseStateHandle<&str>`, which does not implement the `Copy` trait
15 | let oninput = Callback::from(move |input_event: InputEvent| {
| ------------------------------ value moved into closure here
16 | let name = name.clone();
| ---- variable moved due to use in closure
...
29 | <p>{"name: "}<h5>{*name}</h5></p> // <-- here is the error
| ^^^^^ value borrowed here after move
|
= note: borrow occurs due to deref coercion to `&str`
note: deref defined here
--> /home/explorer/.cargo/registry/src/github.com-1ecc6299db9ec823/yew-0.20.0/src/functional/hooks/use_state.rs:128:5
|
128 | type Target = T;
| ^^^^^^^^^^^
The first error is because you need to store String
and not &str
. The second is because you need to clone()
the state before the closure:
#[function_component]
fn App() -> Html {
let name = use_state(|| String::new());
let oninput = Callback::from({
let name = name.clone();
move |input_event: InputEvent| {
let target: HtmlInputElement = input_event
.target()
.unwrap_throw()
.dyn_into()
.unwrap_throw();
//web_sys::console::log_1(&target.value().into()); // <- can console the value.
name.set(target.value());
}
});
html! {
<div>
<input {oninput} />
<p>{"name: "}<h5>{&*name}</h5></p>
</div>
}
}