メインコンテンツにスキップ
バージョン: 0.21

カスタムフック

カスタムフックの定義

コンポーネントの状態ful ロジックは、カスタムフックを作成することで、再利用可能な関数に抽出できます。

window オブジェクトのイベントをリッスンするイベントリスナーを作成したいと想定します。

use yew::prelude::*;
use gloo::events::EventListener;
use gloo::utils::window;
use std::mem::drop;


#[function_component(ShowStorageChanged)]
pub fn show_storage_changed() -> Html {
let state_storage_changed = use_state(|| false);

{
let state_storage_changed = state_storage_changed.clone();
use_effect(|| {
let listener = EventListener::new(&window(), "storage", move |_| state_storage_changed.set(true));

move || { drop(listener); }
});
}

html! { <div>{"Storage Event Fired: "}{*state_storage_changed}</div> }
}

このコードには 1 つ問題があります: 別のコンポーネントではこのロジックを再利用できません。別のイベントをリッスンするコンポーネントを作成する場合、コードをコピーするのではなく、ロジックをカスタムフックに移動できます。

use_event という新しい関数を作成することから始めます。use_ プレフィックスは、関数がフックであることを示します。この関数は、イベントターゲット、イベントタイプ、コールバックを引数として受け取ります。すべてのフックは、関数定義で #[hook] でマークする必要があります。

use web_sys::{Event, EventTarget};
use std::borrow::Cow;
use gloo::events::EventListener;
use yew::prelude::*;

#[hook]
pub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)
where
E: Into<Cow<'static, str>>,
F: Fn(&Event) + 'static,
{
todo!()
}

このシンプルなフックは、組み込みフックを組み合わせることで作成できます。この例では use_effect_with フックを使用するため、フックの引数が変更されたときにイベントリスナーを再作成できます。

use yew::prelude::*;
use web_sys::{Event, EventTarget};
use std::borrow::Cow;
use std::rc::Rc;
use gloo::events::EventListener;

#[hook]
pub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)
where
E: Into<Cow<'static, str>>,
F: Fn(Event) + 'static,
{
#[derive(PartialEq, Clone)]
struct EventDependents {
target: EventTarget,
event_type: Cow<'static, str>,
callback: Callback<Event>,
}

let deps = EventDependents {
target: target.clone(),
event_type: event_type.into(),
callback: Callback::from(callback),
};

use_effect_with(
deps,
|deps| {
let EventDependents {
target,
event_type,
callback,
} = deps.clone();

let listener = EventListener::new(&target, event_type, move |e| {
callback.emit(e.clone());
});

move || {
drop(listener);
}
},
);
}

このアプローチはほとんどの場合で機能しますが、すでに使用している定義済みのフックのような基本フックを作成するために使用することはできません。

ドキュメントについては docs.rs のドキュメントと hooks ディレクトリで事前定義フックの実装を確認します。