Skip to main content
Version: Next

生命週期

Component trait 有許多方法需要實作;Yew 會在元件的生命週期的不同階段呼叫這些方法。

生命週期

改進文檔

生命週期方法

Create

當元件被建立時,它會從其父元件接收屬性,並儲存在傳遞給 create 方法的 Context<Self> 中。這些屬性可以用來初始化元件的狀態,而 "link" 可以用來註冊回呼或傳送訊息給元件。

use yew::{Component, Context, html, Html, Properties};

#[derive(PartialEq, Properties)]
pub struct Props;

pub struct MyComponent;

impl Component for MyComponent {
type Message = ();
type Properties = Props;

fn create(ctx: &Context<Self>) -> Self {
MyComponent
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
// 具體實現
}
}
}

View

view 方法可讓您描述元件應該如何呈現到 DOM 中。使用Rust 函數編寫類似HTML 的程式碼可能會變得非常混亂,因此Yew 提供了一個名為html! 的宏,用於聲明HTML 和SVG 節點(以及將屬性和事件監聽器附加到它們)以及一種方便的方法來渲染子元件。這個宏在某種程度上類似於 React 的 JSX(除了程式語言的差異)。一個不同之處是 Yew 提供了一種類似 Svelte 的屬性的簡寫語法,其中您可以只寫 {onclick},而不用寫 onclick={onclick}

use yew::{Component, Context, html, Html, Properties};

enum Msg {
Click,
}

#[derive(PartialEq, Properties)]
struct Props {
button_text: String,
}

struct MyComponent;

impl Component for MyComponent {
type Message = Msg;
type Properties = Props;

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, ctx: &Context<Self>) -> Html {
let onclick = ctx.link().callback(|_| Msg::Click);
html! {
<button {onclick}>{ &ctx.props().button_text }</button>
}
}
}

就使用上的說明,請查看 html! 指南

Rendered

rendered 元件生命週期方法在 view 被調用並且 Yew 已經將結果渲染到 DOM 中後調用,但在瀏覽器刷新頁面之前。當您想要執行只能在元件渲染元素後完成的操作時,此方法非常有用。還有一個名為 first_render 的參數,可以用來確定此函數是在第一次渲染時調用,還是在後續渲染時調用。

use web_sys::HtmlInputElement;
use yew::{
Component, Context, html, Html, NodeRef,
};

pub struct MyComponent {
node_ref: NodeRef,
}

impl Component for MyComponent {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self {
node_ref: NodeRef::default(),
}
}

fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<input ref={self.node_ref.clone()} type="text" />
}
}

fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {
input.focus();
}
}
}
}
note

請注意,此生命週期方法不需要實現,並且預設不會執行任何操作。

Update

與組件的通訊主要透過訊息進行,這些訊息由 update 生命週期方法處理。這允許元件根據訊息更新自身,並確定是否需要重新渲染自身。訊息可以由事件監聽器、子元件、Agents、Services 或 Futures 傳送。

下面是 update 的實作範例:

use yew::{Component, Context, html, Html};

pub enum Msg {
SetInputEnabled(bool)
}

struct MyComponent {
input_enabled: bool,
}

impl Component for MyComponent {
type Message = Msg;
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self {
input_enabled: false,
}
}

fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::SetInputEnabled(enabled) => {
if self.input_enabled != enabled {
self.input_enabled = enabled;
true // 重新渲染
} else {
false
}
}
}
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
// 具體實現
}
}

}

Changed

元件可能會被其父元件重新渲染。當這種情況發生時,它們可能會接收新的屬性並需要重新渲染。這種設計透過僅更改屬性的值來促進父子組件之間的通訊。當屬性更改時,有一個預設實作會重新渲染元件。

Destroy

元件從 DOM 卸載後,Yew 會呼叫 destroy 生命週期方法;如果您需要在元件被銷毀之前執行清理操作,這是必要的。此方法是可選的,預設不執行任何操作。

無限循環

無限循環在 Yew 的生命週期方法中是可能的,但只有在嘗試在每次渲染後更新相同的元件時,當更新也要求重新渲染元件時才會發生。

下面是一個簡單的範例:

use yew::{Context, Component, Html};

struct Comp;

impl Component for Comp {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
// 我們總是請求在任何訊息上重新渲染
true
}

fn view(&self, _ctx: &Context<Self>) -> Html {
// 無論渲染什麼都不重要
Html::default()
}

fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
// 請求使用此新訊息更新元件
ctx.link().send_message(());
}
}

讓我們看看這裡發生了什麼:

  1. 使用 create 函數建立元件。
  2. 呼叫 view 方法,以便 Yew 知道要渲染到瀏覽器 DOM 中的內容。
  3. 呼叫 rendered 方法,使用 Context 連結安排更新訊息。
  4. Yew 完成後渲染階段。
  5. Yew 檢查已排程的事件,並看到更新訊息佇列不為空,因此處理訊息。
  6. 呼叫 update 方法,回傳 true 表示發生了變化,元件需要重新渲染。
  7. 跳回第 2 步。

您仍然可以在 rendered 方法中安排更新,這通常是有用的,但是在這樣做時,請考慮您的元件將如何終止此循環。

關聯類型

Component trait 有两个关联类型:MessageProperties

impl Component for MyComponent {
type Message = Msg;
type Properties = Props;

// ...
}

Message 類型用於在事件發生後向元件發送訊息;例如,您可能希望在使用者點擊按鈕或向下捲動頁面時執行某些操作。因為元件通常需要回應多個事件,所以 Message 類型通常是一個枚舉,其中每個變體都是要處理的事件。

在組織程式碼庫時,將 Message 類型的定義包含在定義元件的相同模組中是明智的。您可能會發現採用一致的命名約定來命名訊息類型很有幫助。一個選項(儘管不是唯一的選項)是將類型命名為 ComponentNameMsg,例如,如果您的元件名為 Homepage,則可以將類型命名為 HomepageMsg

enum Msg {
Click,
FormInput(String)
}

Properties 表示從其父元件傳遞給元件的訊息。此類型必須實作 Properties trait(通常透過衍生它)並且可以指定某些屬性是必需的還是可選的。在建立和更新元件時使用此類型。在組件的模組中建立一個名為 Props 的結構體,並將其用作組件的 Properties 類型是一種常見做法。通常將 "properties" 縮寫為 "props"。由於 props 是從父元件傳遞下來的,因此應用程式的根元件通常具有 Properties 類型為 ()。如果要為根元件指定屬性,請使用 App::mount_with_props 方法。

生命週期上下文

所有組件生命週期方法都接受一個上下文物件。此物件提供了對元件作用域的引用,允許向元件發送訊息並傳遞給元件的 props。