Matt 90b4e55ebc
Docusaurus Overhaul (#2275)
* change suffixes from md to mdx
fix broken links for English locale
tree shake and update docusaurus
add docusaurus ideal image plugin
use svg and themed image
delete unused static asset

* move localized landing page

* change GitLocalize project page

* nit pick

* remove ignore to have the block checked
2021-12-20 12:10:45 +02:00

89 lines
2.9 KiB
Plaintext

---
title: "Custom Hooks"
description: "Defining your own Hooks "
---
## Defining custom Hooks
Component's stateful logic can be extracted into usable function by creating custom Hooks.
Consider that we have a component which subscribes to an agent and displays the messages sent to it.
```rust
use yew::{function_component, html, use_effect, use_state, Callback};
use yew_agent::Bridged;
// EventBus is an implementation yew_agent::Agent
use website_test::agents::EventBus;
#[function_component(ShowMessages)]
pub fn show_messages() -> Html {
let state = use_state(Vec::new);
{
let state = state.clone();
use_effect(move || {
let producer = EventBus::bridge(Callback::from(move |msg| {
let mut messages = (*state).clone();
messages.push(msg);
state.set(messages)
}));
|| drop(producer)
});
}
let output = state.iter().map(|it| html! { <p>{ it }</p> });
html! { <div>{ for output }</div> }
}
```
There's one problem with this code: the logic can't be reused by another component.
If we build another component which keeps track of the messages, instead of copying the code we can move the logic into a custom hook.
We'll start by creating a new function called `use_subscribe`.
The `use_` prefix conventionally denotes that a function is a hook.
This function will take no arguments and return `Rc<RefCell<Vec<String>>>`.
```rust
use std::{cell::RefCell, rc::Rc};
fn use_subscribe() -> Rc<RefCell<Vec<String>>> {
todo!()
}
```
This is a simple hook which can be created by combining other hooks. For this example, we'll two pre-defined hooks.
We'll use `use_state` hook to store the `Vec` for messages, so they persist between component re-renders.
We'll also use `use_effect` to subscribe to the `EventBus` `Agent` so the subscription can be tied to component's lifecycle.
```rust
use std::collections::HashSet;
use yew::{use_effect, use_state, Callback};
use yew_agent::Bridged;
// EventBus is an implementation yew_agent::Agent
use website_test::agents::EventBus;
fn use_subscribe() -> Vec<String> {
let state = use_state(Vec::new);
let effect_state = state.clone();
use_effect(move || {
let producer = EventBus::bridge(Callback::from(move |msg| {
let mut messages = (*effect_state).clone();
messages.push(msg);
effect_state.set(messages)
}));
|| drop(producer)
});
(*state).clone()
}
```
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
### Writing primitive hooks
`use_hook` function is used to write such hooks. View the docs on [docs.rs](https://docs.rs/yew/0.18.0/yew-functional/use_hook.html) for the documentation
and `hooks` directory to see implementations of pre-defined hooks.