跳至主要内容
版本:0.21

属性

注意

属性通常缩写为“Props”。

属性本质上是 Yew 可以监视的组件参数。

在将类型用作组件的属性之前,必须实现Properties 特性。

响应性

在重新渲染期间协调虚拟 DOM 时,Yew 会检查道具是否已更改,以了解是否需要重新渲染嵌套组件。通过这种方式,Yew 可以被认为是一个非常响应的框架,因为父级中的更改将始终向下传播,并且视图永远不会与来自道具/状态的数据不同步。

提示

如果您尚未完成教程,请尝试一下并自己测试这种响应性!

派生宏

Yew 提供了一个派生宏,可以轻松地在结构上实现Properties 特性。

为其派生Properties 的类型还必须实现PartialEq,以便 Yew 可以进行数据比较。

use yew::Properties;

#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}

在函数组件中使用

属性#[function_component]允许在函数参数中接收 Props。要提供它们,它们通过html!宏中的属性进行分配。

use yew::{function_component, html, Html, Properties};

#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}

#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! { <>{"Am I loading? - "}{props.is_loading.clone()}</> }
}

// Then supply the prop
#[function_component]
fn App() -> Html {
html! {<HelloWorld is_loading={true} />}
}

派生宏字段属性

派生Properties 时,默认情况下所有字段都是必需的。以下属性允许您为道具提供默认值,当父级未设置这些值时将使用这些值。

提示

属性在 Rustdoc 生成的文档中不可见。属性的文档字符串应提及道具是否可选以及是否具有特殊的默认值。

使用 Default 特性,使用字段类型的默认值初始化 prop 值。

use yew::{function_component, html, Html, Properties};

#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or_default]
pub is_loading: bool,
}

#[function_component]
fn HelloWorld(props: &Props) -> Html {
if props.is_loading.clone() {
html! { "Loading" }
} else {
html! { "Hello world" }
}
}

// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld is_loading={true} />}
}

使用属性的内存/速度开销

内部属性是引用计数的。这意味着仅将共享指针向下传递到组件树以获取 prop。这使我们节省了克隆整个 prop 的成本,这可能是昂贵的。

提示

利用 AttrValue,这是我们自定义的属性值类型,而不是将它们定义为 String 或其他类似类型。

Prop 宏

yew::props! 宏允许你以与 html! 宏相同的方式构建属性。

该宏使用与结构表达式相同的语法,但你不能使用属性或基本表达式 (Foo { ..base })。类型路径可以指向 prop 本身 (path::to::Props) 或组件的相关属性 (MyComp::Properties)。

use yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};

#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or(AttrValue::from("Bob"))]
pub name: AttrValue,
}

#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
}

#[function_component]
fn App() -> Html {
let pre_made_props = props! {
Props {} // Notice we did not need to specify name prop
};
html! {<HelloWorld ..pre_made_props />}
}

计算顺序

Prop 按指定顺序计算,如下例所示

#[derive(yew::Properties, PartialEq)]
struct Props { first: usize, second: usize, last: usize }

fn main() {
let mut g = 1..=3;
let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });

assert_eq!(props.first, 1);
assert_eq!(props.second, 2);
assert_eq!(props.last, 3);
}

反模式

虽然几乎任何 Rust 类型都可以作为属性传递,但有一些反模式应该避免。这些包括但不限于

  1. 使用 String 类型,而不是 AttrValue

    为什么这样做不好? String 克隆成本较高。当 prop 值与钩子和回调一起使用时,通常需要克隆。AttrValue 是引用计数字符串 (Rc<str>) 或 &'static str,因此克隆成本很低。

    注意AttrValue 内部是 implicit-clone 中的 IString。请参阅该 crate 以了解更多信息。
  2. 使用内部可变性。

    为什么这样做不好? 通常情况下,应避免使用内部可变性(例如 RefCellMutex 等)。它可能会导致重新渲染问题(Yew 不知道状态何时已更改),因此你可能必须手动强制渲染。与所有事物一样,它有其用途。请谨慎使用。
  3. 你告诉我们。你是否遇到了希望早点了解到的极端情况?请随时创建问题或 PR 来修复此文档。

yew-autoprops

yew-autoprops 是一个实验性包,它允许你根据函数的参数动态创建 Props 结构。如果从未重复使用过属性结构,它可能会很有用。