生命週期
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(());
}
}
讓我們仔細瀏覽這裡的執行情形
- 使用
create
函數建立組件。 - 呼叫
view
方法,讓 Yew 知道要渲染哪些內容到瀏覽器的 DOM。 - 呼叫
rendered
方法,排定使用Context
鏈結的更新訊息。 - Yew 完成後渲染階段。
- Yew 檢查排程的工作,發現更新訊息佇列不為空,因此執行訊息。
- 呼叫
update
方法,傳回true
來表示有東西有所變更,且組件需要重新渲染。 - 跳回步驟 2。
你仍可以在 rendered
方法中排定更新,且這樣做通常很有用,但請考慮你的組件在這麼做時將如何終止這個迴圈。
相關型別
Component
特質具有兩種相關型別:Message
與 Properties
。
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。