跳到主要內容
版本:0.21

生命週期

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

生命週期

貢獻

對我們的文件作出貢獻: 加入組件生命週期圖表

生命週期方法

建立

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

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! {
// impl
}
}
}

檢視

``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` 元件生命週期方法會在呼叫 `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();
}
}
}
}
注意

請注意,這個生命週期方法不需實作,預設不會有任何動作。

更新

與元件主要透過訊息來進行通訊,由 `update` 生命週期方法處理。這樣一來,元件就能根據訊息來更新自己,並判斷自己是否需要重新呈現。訊息可以由事件聆聽器、子元件、Agent、服務或 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 // Re-render
} else {
false
}
}
}
}

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

}

已變更

組件可能會被其父代重新渲染。這樣做時,它們可能會收到新的屬性並需要重新渲染。這種設計透過僅變更屬性的值即可促進父代到子代組件間的 通訊。有一個預設實作,在道具變更時重新渲染組件。

「銷毀」

在組件從 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 {
// We are going to always request to re-render on any msg
true
}

fn view(&self, _ctx: &Context<Self>) -> Html {
// For this example it doesn't matter what is rendered
Html::default()
}

fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
// Request that the component is updated with this new msg
ctx.link().send_message(());
}
}

讓我們仔細瀏覽這裡的執行情形

  1. 使用 create 函數建立組件。
  2. 呼叫 view 方法,讓 Yew 知道要渲染哪些內容到瀏覽器的 DOM。
  3. 呼叫 rendered 方法,排定使用 Context 鏈結的更新訊息。
  4. Yew 完成後渲染階段。
  5. Yew 檢查排程的工作,發現更新訊息佇列不為空,因此執行訊息。
  6. 呼叫 update 方法,傳回 true 來表示有東西有所變更,且組件需要重新渲染。
  7. 跳回步驟 2。

你仍可以在 rendered 方法中排定更新,且這樣做通常很有用,但請考慮你的組件在這麼做時將如何終止這個迴圈。

相關型別

Component 特質具有兩種相關型別:MessageProperties

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

// ...
}

Message 型別用於在事件發生後傳送訊息至組件;例如,你可能想要在使用者按下按鈕或捲動頁面時執行一些動作。由於組件通常必須回應多個事件,因此 Message 型別通常會是列舉,其中每個變體都是要處理的事件。

在組織你的程式碼庫時,將 Message 型別的定義與定義你組件的同一個模組中包含起來是明智的。針對訊息型別採用統一的命名慣例可能會對你有幫助。一種選項(但不是唯一的選項)是將型別命名為 ComponentNameMsg,例如,如果你的組件稱為 Homepage,則你可以將型別稱為 HomepageMsg

enum Msg {
Click,
FormInput(String)
}

屬性表示組件從其父組件傳入的資訊。此類型必須實作屬性特徵(通常通過繼承它),並且可以指定某些屬性是必需還是可選的。此類型用於建立和更新組件。在你組件的模組中建立一個名為Props的結構,並將其作為組件的屬性類型是一種常見做法。經常縮寫「屬性」為「props」。由於 props 是由父組件傳遞的,因此應用程式的根組件通常有一個屬性類型為()。如果你想要為你的根組件指定屬性,請使用App::mount_with_props方法。

生命週期內容

所有組件生命週期方法都會取得一個內容物件。此物件提供對組件範圍的參考,可傳送訊息給組件和傳給組件的 props。