I'm currently using Dioxus to generate a page that dynamically changes an image carousel.
What I want to achieve right now is to use the max
function to compare the result of use_state
to prevent the number from coming lower from 1.
Here's a simple app:
use dioxus::{events::*, hooks::UseState, prelude::*};
use log::{info, LevelFilter};
use std::cmp::{max, Ordering};
impl PartialOrd for UseState<i32> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for UseState<i32> {
fn cmp(&self, other: &Self) -> Ordering {
self.x.cmp(&other.x)
}
}
/**
* Specify <link data-trunk rel="copy-dir" href="src/assets" />
* in the index.html to copy the files!!
*
* You'll see them in the dist directory!
*/
fn main() {
dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
dioxus::web::launch(app);
}
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let val = index.get() as &i32;
let num = 1 as i32;
let change_evt = move |evt: KeyboardEvent| match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index = max(&num.try_into(), &val.try_into()),
_ => {}
};
let url = format!("/assets/manga/one_piece/1042/0{}.jpg", index);
cx.render(rsx!(img {
src: "{url}",
}
div {
class: "display",
onkeydown: change_evt,
button {
class: "but",
onclick: move |evt| {
println!("{evt:?}");
info!("{evt:?}");
},
"Press me!"
},
},
))
}
I thought at the beginning that using index.get()
would yield me the i32
needed to compare with max()
.
But it complained and told me I needed to implement PartialOrd
for UseState{Integer}
.
I'm currently stuck trying to implement it.
Here's my cargo.toml
[package]
name = "rust-manga"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus = { version = "0.2.4", features = ["web", "html"] }
dioxus-html = "0.2.1"
dioxus-logger = "0.3.0"
log = "0.4.17"
When implementing a trait for something (such as impl PartialOrd for UseState
), then at least one of the two components must belong to the crate where the impl
is defined. But both PartialOrd
and UseState
are defined outside your crate, so you cannot do that.
There are two options:
struct MyUseState<T: 'static>(UseState<T>);
impl<T> PartialOrd for MyUseState<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
The downside is that you would need to wrap instances of where you use dioxus::hooks::UseState
in your custom type, at least whenever you want to compare things.
UseState
:If UseState
doesn't implement the traits necessary to pass it to std::cmp::max
, we have to get the inner value. It does offer multiple ways to do that, such as UseState::get()
, UseState::current()
or an implementation of Deref
.
So we could do max(num, *index.get())
, where .get()
gets a &i32
, and we derefence that to get the value. Or max(num, **index)
, using Deref
.
However, we still can't assign that to index
, as an i32
can't be assigned to an UseState
.
That's what UseState::modify()
is for. It allows you to modify the value in place:
// Again, `.modify()` only gives a reference to the closure, which we have to derefence.
index.modify(|val| max(num, *val))