ライフサイクル
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とSVGノードの宣言(属性とイベントリスナーの添付を含む)、および子コンポーネントをレンダリングするための便利な方法としてhtml!
というマクロを提供します。このマクロは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
ライフサイクルメソッドによって処理されるメッセージを通じて行われます。これにより、コンポーネントはメッセージの内容に基づいて自身を更新し、再レンダリングが必要かどうかを判断できます。メッセージは、イベントリスナー、子コンポーネント、エージェント、サービス、またはFutureによって送信できます。
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
の2つの関連型があります。
impl Component for MyComponent {
type Message = Msg;
type Properties = Props;
// ...
}
Message
型は、イベントが発生した後にコンポーネントにメッセージを送信するために使用されます。たとえば、ユーザーがボタンをクリックしたときやページをスクロールしたときに何らかのアクションを実行したい場合があります。コンポーネントは複数のイベントに対応する必要があるため、Message
型は通常、各バリアントが処理されるイベントである列挙型になります。
コードベースを整理する際には、コンポーネントが定義されているのと同じモジュールにMessage
型の定義を含めることが賢明です。メッセージ型の一貫した命名規則を採用すると役立つ場合があります。1つのオプション(唯一のオプションではありません)は、型をComponentNameMsg
と名付けることです。たとえば、コンポーネントがHomepage
と呼ばれている場合、型をHomepageMsg
と呼ぶことができます。
enum Msg {
Click,
FormInput(String)
}
Properties
は、親コンポーネントからコンポーネントに渡される情報を表します。この型はProperties
トレイトを実装する必要があり(通常はそれを導出することによって)、特定のプロパティが必要かどうかを指定できます。この型は、コンポーネントの作成と更新に使用されます。コンポーネントのモジュールでProps
という構造体を作成し、それをコンポーネントのProperties
型として使用するのが一般的です。「properties」を「props」と略すのが一般的です。propsは親コンポーネントから渡されるため、アプリケーションのルートコンポーネントのProperties
型は通常()
です。ルートコンポーネントにプロパティを指定する場合は、App::mount_with_props
メソッドを使用します。
ライフサイクルコンテキスト
すべてのコンポーネントライフサイクルメソッドは、コンテキストオブジェクトを受け取ります。このオブジェクトはコンポーネントのスコープへの参照を提供し、コンポーネントへのメッセージの送信とコンポーネントに渡されるpropsを可能にします。