Dioxus 开发指南

组件道具

所有用于组件的道具都必须 Properties 特征,而 Props 派生宏则可以自动实现它。

在本章中我们会了解到:

  • 使用 Props 宏
  • 记忆 Memoization
  • 可选的道具
  • Inline_props 宏

使用 Props 宏§

默认的 Scope 不包含任何数据:

// 这是一个不包含任何道具的 Scope
Scope<()>
// 它和上面的不包含数据的 Scope 相等
Scope

接下来我们定义一个 Props,你需要声明一个结构体,并为它添加派生宏。

#[derive(Props)]
struct MyProps {
    name: String
}

上方的代码并不能被编译,因为结构体中没有任何借用,那则需要实现 PartialEq

#[derive(Props, PartialEq)]
struct MyProps {
    name: String
}

或者包含借用的:

#[derive(Props)]
struct MyProps<'a> {
    name: &'a str
}

接下来我们将 MyProps 引入到我们的组件中,并使用它:

fn Demo(cx: Scope<MyProps>) -> Element {
    todo!()
}

如果是包含借用的:

fn Demo<'a>(cx: Scope<'a, MyProps<'a>>) -> Element {
    todo!()
}

记忆 Memoization§

如果你来自 React 框架,那么你应该会蛮好奇我们是怎么处理 Memoization 的:

Memoization: 一种在数据被更新时,重新渲染页面的优化技术。 当页面被频繁刷新时,性能和用户体验都会大大降低,这时候就需要一些方法来完成优化。

当一个道具值被更改,但它并不会影响到输出内容,那我们便不会刷新页面渲染。

比如:

fn Demo(cx: Scope) -> Element {
    let (name, _set_name) = use_state(&cx, || String::from("bob"));
    let (age, _set_age) = use_state(&cx, || 21);

    cx.render(rsx!{
        Name { name: name }
        Age { age: age }
    })
}

Name 被改变时,我们没必要对 Age 也进行刷新,因为它的内容没有任何变化,所以说刷新它只会造成无用的开销。

关于 Memoization 在什么时候有效: 当结构体实现了 PartialEq 时,它会被优化,但是如果结构中包含任何引用,则组件无法被优化,因为我们无法判断引用的 子/父 组件的更新状态。

可选道具§

我们可以为 Dioxus 定义可选的道具(因为在部分情况下,有一些道具可以包含默认值)Dioxus 在这方面的设计借鉴了:Rust-Typed-Builder 的设计。

#[derive(Props, PartialEq)]
struct MyProps {
    
    name: String,

    #[props(optional)]
    description: Option<String>

}

fn Demo(cx: Scope<MyProps>) -> Element {
    // ...
}

可选道具:数据类型必须包含 Default 特征,在没有被赋值的时候,会为默认值。

optional 修饰符包含了两个独立的修饰符 defaultstrip_option

以下是完整的修饰符列表:

  • default - 当内容没有填写时,赋予它默认值。
  • strip_option - 自动包装 Some 数据。
  • optional - 同时包含了 defaultstrip_option 修饰符。
  • into - 在调用时自动调用 into() 函数。

inline_props 宏§

我们提供了 inline_props 宏,它将允许你在函数参数中设置 Props

#[derive(Props, PartialEq)]
struct TitleCardProps {
    title: String,
}

fn TitleCard(cx: Scope<TitleCardProps>) -> Element {
    cx.render(rsx!{
        h1 { "{cx.props.title}" }
    })
}   

也可以写成这样:

#[inline_props]
fn TitleCard(cx: Scope, title: String) -> Element {
    cx.render(rsx!{
        h1 { "{title}" }
    })
}  

我们认为库作者不应该在项目中使用这个宏,因为它无法实现 可选 功能,同时你无法更好的为组件编写文档。