自定义挂钩
定义自定义 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 的实现。