Muhammad Hamza 5e823e729d
Prepare for 0.21 release (#3412)
* Update CHANGELOG

Changelog run: https://github.com/yewstack/yew/actions/runs/6283917852/job/17064800916

* docusaurus docs:version 0.21

* migration guide

* blog post

* prettier

* make website warnings go away

* make GA work

* Apply suggestions from code review

* Apply suggestion from review

Co-authored-by: Kaede Hoshikawa <futursolo@users.noreply.github.com>

* prettier

---------

Co-authored-by: Kaede Hoshikawa <futursolo@users.noreply.github.com>
2023-09-29 19:10:07 +09:00

114 lines
3.0 KiB
Plaintext

---
title: 'Custom Hooks'
---
## Defining custom Hooks
The stateful logic of a component can be extracted into reusable functions by creating custom Hooks.
Consider that we wish to create an event listener that listens to an event on the `window`
object.
```rust
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> }
}
```
There's one problem with this code: the logic can't be reused by another component.
If we build another component that listens to a different event,
instead of copying the code, we can move the logic into a custom hook.
We'll start by creating a new function called `use_event`.
The `use_` prefix denotes that a function is a hook.
This function will take an event target, an event type, and a callback.
All hooks must be marked by `#[hook]` on their function definition.
```rust
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!()
}
```
This simple hook can be created by composing built-in hooks. For this example, we'll use the
`use_effect_with` hook, so an event listener can be recreated when the hook arguments change.
```rust
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);
}
},
);
}
```
Although this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.
View the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.