Dioxus 互动性

互动性

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

封装状态

在进一步深入之前,我们先将应用程序分成两部分:Title 和 DogView 。这将有助于我们组织应用程序,并将 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_signal 和 Context 结合起来,为应用程序提供反应状态:

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_context 和 consume_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,但重要的是要知道您可以使用这些功能。

相关推荐
遇码9 小时前
流式调用中途断连别直接报错:瞬态故障识别、退避重试与中文根因诊断的搭建方法
大数据·人工智能·ai·rust·数据分析·大模型·agent
DongQiShanRen10 小时前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
alwaysrun17 小时前
Web之wasm-pack详解
前端·rust·web·wasm
DongQiShanRen20 小时前
六根硬件映射(下):物理闭环五步法,抽一条已实装的看
大数据·jvm·人工智能·算法·rust·哈希算法·集成学习
Zenova EdgeOS1 天前
Rust TUI 实战:用 ratatui 构建工业边缘终端界面
开发语言·后端·rust·工业网关
遇码1 天前
不用转场引擎做幻灯片转场:相机滑动、黑场淡入与真全屏的完整做法
人工智能·数码相机·ai·rust·大模型·agent
lpfasd1231 天前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
Flynt1 天前
我把真实的 ES 查询怼到 7059 星的 Rust 搜索引擎上:1366/1369 的兼容承诺,裂了 3 个缝
elasticsearch·搜索引擎·rust
小杍随笔2 天前
egui 0.37 升级实录:卡顿修复与5倍性能回退
windows·rust·egui
geovindu2 天前
rust: Iterator Pattern
开发语言·后端·设计模式·rust·行为模式·迭代器模