Dioxus 互动性

互动性

现在,我们的 HotDog 应用程序已经搭好了脚手架并设计好了样式,我们终于可以添加一些交互元素了。

封装状态

在进一步深入之前,我们先将应用程序分成两部分:TitleDogView 。这将有助于我们组织应用程序,并将 DogView 状态与 Title 状态分开。

rust 复制代码
#[component]
fn App() -> Element {
    rsx! {
        document::Stylesheet { href: CSS }
        Title {}
        DogView {}
    }
}

#[component]
fn Title() -> Element {
    rsx! {
        div { id: "title",
            h1 { "HotDog! 🌭" }
        }
    }
}

#[component]
fn DogView() -> Element {
    rsx! {
        div { id: "dogview",
            img { src: "https://images.dog.ceo/breeds/pitbull/dog-3981540_1280.jpg" }
        }
        div { id: "buttons",
            button { id: "skip", "skip" }
            button { id: "save", "save!" }
        }
    }
}

事件处理程序

DogView 组件中,我们希望为点击按钮附加一个动作。例如:跳过或保存当前的狗狗照片。我们可以使用 EventHandler 来监听点击事件。

事件处理程序与常规属性类似,但它们的名称通常以 on 开头,并接受闭包作为值。每当触发相应事件时,闭包就会被调用。监听器会接收事件对象中的事件信息。

我们将添加一些闭包,然后将它们传递给跳过和保存按钮的 onclick 属性:

rust 复制代码
#[component]
fn DogView() -> Element {
    let skip = move |evt| {};
    let save = move |evt| {};

    rsx! {
        // ...
        div { id: "buttons",
            button { onclick: skip, id: "skip",  "skip" }
            button { onclick: save, id: "save",  "save!" }
        }
    }
}

有关事件处理程序的更多信息,请参阅事件处理程序参考资料

使用use_hook 的状态

到目前为止,我们的组件还没有内部状态。对于 DogView,我们希望在用户点击跳过或保存时更改当前显示的狗狗照片。

为了在组件中存储状态,Dioxus 提供了 use_hook 函数。这使得裸 Rust 函数可以存储和加载状态,而无需使用额外的结构体。

在组件中调用时,use_hook 函数将返回一个原始存储值的 .clone()

rust 复制代码
#[component]
fn DogView() -> Element {
    let img_src = use_hook(|| "https://images.dog.ceo/breeds/pitbull/dog-3981540_1280.jpg");

    // ..

    rsx! {
        div { id: "dogview",
            img { src: "{img_src}" }
        }
        // ..
    }
}

Dioxus 钩子与 React 的钩子非常相似,需要遵循一些简单的规则才能正常运行。

信号和使用信号

虽然 use_hook 可以存储任何实现了 Clone 的值,但您经常需要一种更强大的状态管理方式。Dioxus 内置了信号。

信号 是普通 Rust 值的封装类型,它可以跟踪读写,让你的应用程序栩栩如生。你可以在信号中封装任何 Rust 值。信号可以通过 Signal::new() 手动创建,但我们强烈建议使用 use_signal 钩子。

手动创建信号需要记住在信号上调用 .manually_drop(),而 use_signal 会自动为你清理信号。

每当信号的值发生变化时,其包含的 "反应范围 "就会被 "标记为脏 "并重新运行。默认情况下,Dioxus 组件都是反应式作用域,因此只要信号值发生变化,就会重新渲染。

信号是 Dioxus 的核心 ,需要时间来掌握。我们建议您在开发第一个大型应用程序之前深入阅读状态管理指南

全局状态与上下文

虽然钩子能很好地管理组件的本地状态,但有时您也需要管理整个应用程序的状态。

Dioxus 提供了两种机制:上下文(Context )和全局信号(GlobalSignal)。

通过 Context API,父组件可以与子组件共享状态,而无需明确声明额外的属性字段。大型应用程序和程序库可利用这种机制在整个应用程序中共享状态,而无需修改组件签名。

要 "provide "上下文,只需使用实现 Clone 的结构调用 use_context_provider()。要读取子代中的上下文,请调用 use_context()

rust 复制代码
// Create a new wrapper type
#[derive(Clone)]
struct TitleState(String);

fn App() -> Element {
    // Provide that type as a Context
    use_context_provider(|| TitleState("HotDog".to_string()));
    rsx! {
        Title {}
    }
}

fn Title() -> Element {
    // Consume that type as a Context
    let title = use_context::<TitleState>();
    rsx! {
        h1 { "{title.0}" }
    }
}

您可以将 use_signalContext 结合起来,为应用程序提供反应状态:

rust 复制代码
#[derive(Clone, Copy)]
struct MusicPlayer {
    song: Signal<String>,
}

fn use_music_player_provider() {
    let song = use_signal(|| "Drift Away".to_string());
    use_context_provider(|| MusicPlayer { song });
}

通过 use_contextconsume_context,您可以轻松地修改该状态:

rust 复制代码
#[component]
fn Player() -> Element {
    rsx! {
        button {
            onclick: move |_| consume_context::<MusicPlayer>().song.set("Vienna".to_string()),
            "Shuffle"
        }
    }
}

当数值发生变化时,读取歌曲信号的任何组件都会自动重新渲染。

全局信号

有时您需要一个简单的全局值。这时,全局信号(GlobalSignal )就能帮上忙。GlobalSignals 是上下文系统和信号的组合,不需要额外的结构或设置。

只需在应用程序中声明一个 GlobalSignal 即可:

rust 复制代码
static SONG: GlobalSignal<String> = Signal::global(|| "Drift Away".to_string());

然后在任何地方读写:

rust 复制代码
#[component]
fn Player() -> Element {
    rsx! {
        h3 { "Now playing {SONG}" }
        button {
            onclick: move |_| *SONG.write() = "Vienna".to_string(),
            "Shuffle"
        }
    }
}

📣 GlobalSignals 只对一个应用程序具有全局性,而不是整个程序。在服务器上,每个应用程序都有自己的 GlobalSignal

对于 HotDog 来说,我们不需要 GlobalSignal 或 Context,但重要的是要知道您可以使用这些功能。

相关推荐
JVM高并发4 小时前
Nginx使用 Lua 脚本调用外部 API 验证 Token
nginx·全栈
xiaoyan20154 小时前
基于tauri2.0+vue3.5+deepseek+arco搭建wins版流式输出AI系统
vue.js·rust·deepseek
Starduster5 小时前
smol源码解析1 序
后端·rust·源码
好奇的菜鸟5 小时前
Rust 中的宏与函数
开发语言·后端·rust
好奇的菜鸟5 小时前
Rust 项目文档生成之旅:cargo doc
开发语言·后端·rust
好奇的菜鸟8 小时前
如何重新安装 Rust
开发语言·后端·rust
KENYCHEN奉孝15 小时前
使用 Rust Clippy 的详细方案
rust·clippy
加密社1 天前
Solana 开发实战:Rust 客户端调用链上程序全流程
开发语言·后端·rust
Source.Liu1 天前
【unitrix】 3.3 算术取负运算(neg.rs)
rust