Skip to main content
Version: Next

屬性 (Properties)

備註

屬性 (Properties) 通常被簡寫為 "Props"。

屬性 (Properties) 是元件的參數,Yew 可以監視這些參數。

在元件的屬性中使用一個類型之前,它必須實作 Properties trait。

響應性

在重新渲染時,Yew 在協調虛擬 DOM 時檢查屬性是否已更改,以了解是否需要重新渲染巢狀元件。這樣,Yew 可以被認為是一個非常具有響應性的框架,因為來自父組件的變更總是會向下傳播,視圖永遠不會與來自屬性/狀態的資料不同步。

提示

如果您尚未完成 教學,請嘗試並自行測試這種回應性!

派生宏

Yew 提供了一個衍生宏,可以輕鬆地在結構體上實作 Properties trait。

您衍生 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 { is_loading }: &Props) -> Html {
html! { <>{"Am I loading? - "}{is_loading}</> }
}

// 然後提供屬性
#[function_component]
fn App() -> Html {
html! { <HelloWorld is_loading=true /> }
}

派生巨集欄位屬性

在派生 Properties 時,預設情況下所有欄位都是必要的。

以下屬性可讓您為屬性提供預設值,當父元件沒有設定它們時將使用這些預設值。

提示

屬性在 Rustdoc 產生的文檔中是不可見的。您的屬性的文檔字串應該提到一個屬性是否是可選的,以及它是否有一個特殊的預設值。

使用 Default trait 的欄位類型的預設值初始化屬性值。

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 { is_loading }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { "Hello world" }
}
}

// 這樣使用預設值
#[function_component]
fn Case1() -> Html {
html! { <HelloWorld /> }
}
// 或不覆蓋預設值
#[function_component]
fn Case2() -> Html {
html! { <HelloWorld is_loading=true /> }
}

使用 Properties 的效能開銷

內部屬性是以引用計數的智慧型指標傳遞的。這意味著只有一個共享指標被傳遞到元件樹中的屬性,這樣就能節約克隆整個屬性的高昂成本。

提示

AttrValue 是我們用於屬性值的自訂類型,這樣就不用將它們定義為 String 或其他類似克隆成本高昂的類型了。

Props 巨集

yew::props! 巨集允許您以與 html! 巨集相同的方式建立屬性。

這個巨集使用與結構表達式相同的語法,只是您不能使用屬性或基本表達式 (Foo { ..base })。類型路徑可以直接指向屬性 (path::to::Props),也可以指向元件的關聯屬性 (MyComp::Properties)。

use yew::prelude::*;

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

#[function_component]
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{"Hello "}{name}</> }
}
}

#[function_component]
fn App() -> Html {
let pre_made_props = yew::props! {
Props {} // 注意我們不需要指定 name 屬性
};
html! { <Hello ..pre_made_props /> }
}

自動產生屬性 (yew-autoprops)

為了簡化您的開發流程,您也可以使用巨集 #[autoprops](來自 yew-autoprops 套件)自動產生 Properties 結構體。

use yew::prelude::*;
use yew_autoprops::autoprops;

// #[autoprops] 巨集必須出現在 #[function_component] 之前,順序很重要
#[autoprops]
#[function_component]
fn Greetings(
#[prop_or_default]
is_loading: bool,
#[prop_or(AttrValue::Static("Hello"))]
message: &AttrValue,
#[prop_or(AttrValue::Static("World"))]
name: &AttrValue,
) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{message}{" "}{name}</> }
}
}

// 結構體 "GreetingsProps" 將會自動產生。
//
// `is_loading` 將作為值傳遞給元件,而 `message` 和 `name` 將使用引用,因為定義中有一個前導的 `&`。

評估順序

屬性依照指定的順序進行評估,如下例所示:

#[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 克隆成本高。當屬性值與鉤子和回調一起使用時,通常需要克隆。 AttrValue 是一個引用計數的字串 (Rc<str>) 或一個 &'static str,因此非常便宜克隆。
    注意AttrValue 在內部是來自 implicit-cloneIString。查看該包以了解更多資訊。
  2. 使用內部可變性。
    **為什麼不好? ** 內部可變性(例如 RefCellMutex 等)應該 通常 避免使用。它可能會導致重新渲染問題(Yew 不知道狀態何時發生了變化),因此您可能需要手動強制重新渲染。就像所有事物一樣,它有其用武之地。請謹慎使用。
  3. 使用 Vec 型別而不是 IArray
    **為什麼不好? ** Vec,就像 String 一樣,克隆成本也很高。 IArray 是一個引用計數的切片 (Rc<T>) 或一個 &'static [T],因此非常便宜克隆。
    注意IArray 可以從 implicit-clone 匯入。查看該包以了解更多資訊。
  4. 您發覺可能的新內容。您是否遇到了一個希望早點了解清楚的邊緣情況?請隨時建立一個問題或向本文檔提供修復的 PR。

yew-autoprops

yew-autoprops 是一個實驗性包,可讓您根據函數的參數動態建立 Props 結構體。如果屬性結構體永遠不會被重複使用,這可能會很有用。