自訂 Hook
定義自訂 Hook
建立自訂 Hook 可將元件的狀態邏輯擷取出,成為可重複使用的函式。
假設我們想要建立一個事件聆聽器,用來聆聽 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> }
}
此程式碼有一個問題:其邏輯無法由其他元件重複使用。如果我們建立另一個聆聽不同事件的元件,與其複製程式碼,我們可以將其邏輯移至自訂 hook 中。
我們會先建立一個名為 use_event
的新函式。use_
前綴表示該函式是一個 hook。此函式將接收一個事件目標、一個事件型別和一個回呼函式。所有 hook 都必須在其函式定義上加上 #[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!()
}
這個簡單的 hook 可以透過組合內建 hook 產生。針對此範例,我們將使用 use_effect_with
hook,如此一來,當 hook 自變數變更時就能重新產生一個事件聆聽器。
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);
}
},
);
}
儘管這個方法在大部分情況下都能運作,但不能夠用來撰寫如我們一直以來使用的預先定義 Hook 這類原始 Hook。
查看 docs.rs 上的文件,取得文件和 hooks
目錄,查看預先定義 Hook 的應用。