Overview of Yew Hooks
mainreact-use, alibaba/hooks, and vueuse/vueuse. It provides a wide range of utilities for managing state, side-effects, lifecycles, animations, sensors, and UI interactions in Yew applications.repository·main·Indexed 41 days ago
https://github.com/jetli/yew-hooksA comprehensive library of reusable hooks for the Yew web framework, version 0.6.4. Inspired by react-use and vueuse, it provides utilities for state management (e.g., use_counter, use_list), side-effects (e.g., use_async, use_websocket), lifecycle handling, animations, browser sensors, and UI interactions.
react-use, alibaba/hooks, and vueuse/vueuse. It provides a wide range of utilities for managing state, side-effects, lifecycles, animations, sensors, and UI interactions in Yew applications.To execute the project's unit tests in a headless Chrome environment, use wasm-pack test with the --headless and --chrome flags.
wasm-pack test --headless --chrometrunk serve. This command builds the project and opens it in a new browser tab, automatically reloading the page whenever changes are detected in the project files.trunk servetrunk build. This command compiles the project and places the resulting assets into the dist folder.trunk buildThe UseDropHandle returned by use_drop and use_drop_with_options contains several UseStateHandle fields that allow you to react to the drop state in your component's render logic:
over: A UseStateHandle<bool> that is true when a drag operation is currently occurring over the drop zone, and false otherwise.files: A UseStateHandle<Option<Vec<File>>> containing the list of web_sys::File objects from the most recent file drop.text: A UseStateHandle<Option<String>> containing the text content from the most recent text drop or paste.uri: A UseStateHandle<Option<String>> containing the URI string from the most recent URI drop.Note that these handles are updated whenever a successful drop or paste event occurs.
The use_async hook manages the state of an asynchronous task. It tracks whether the task is currently loading, provides the resulting data (if successful), and captures any error encountered. You can trigger the execution of the async task manually by calling .run() on the returned handle.
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use yew::prelude::*;
use yew_hooks::prelude::*;
#[function_component(UseAsync)]
pub fn async_demo() -> Html {
// The async block passed to use_async defines the task
let state = use_async(async move { fetch_repo("jetli/yew-hooks".to_string()).await });
let onclick = {
let state = state.clone();
Callback::from(move |_| {
// Trigger the task manually
state.run();
})
};
html! {
<div>
<button {onclick} disabled={state.loading}>{ "Start to load repo: jetli/yew-hooks" }</button>
<p>
{
if state.loading {
html! { "Loading, wait a sec..." }
} else {
html! {}
}
}
</p>
{
if let Some(repo) = &state.data {
html! {
<>
<p>{ "Repo name: " }<b>{ &repo.name }</p>
<p>{ "Repo full name: " }<b>{ &repo.full_name }</p>
<p>{ "Repo description: " }<b>{ &repo.description }</p>
<p>{ "Owner name: " }<b>{ &repo.owner.login }</p>
<p>{ "Owner avatar: " }<b><br/><img alt="avatar" src={repo.owner.avatar_url.clone()} /></b/></p>
</>
}
} else {
html! {}
}
}
<p>
{
if let Some(error) = &state.error {
match error {
Error::DeserializeError => html! { "DeserializeError" },
Error::RequestError => html! { "RequestError" },
}
} else {
html! {}
}
}
</p>
</div>
}
}The use_counter hook provides a simple way to manage a numeric counter state. It returns a handle that allows you to increment, decrement, set, or reset the value. The handle can be cloned and moved into callbacks.
use yew::prelude::*;
use yew_hooks::prelude::*;
#[function_component(Counter)]
fn counter() -> Html {
let counter = use_counter(0);
let onincrease = {
let counter = counter.clone();
Callback::from(move |_| counter.increase())
};
let ondecrease = {
let counter = counter.clone();
Callback::from(move |_| counter.decrease())
};
let onincreaseby = {
let counter = counter.clone();
Callback::from(move |_| counter.increase_by(10))
};
let ondecreaseby = {
let counter = counter.clone();
Callback::from(move |_| counter.decrease_by(10))
};
let onset = {
let counter = counter.clone();
Callback::from(move |_| counter.set(100))
};
let onreset = {
let counter = counter.clone();
Callback::from(move |_| counter.reset())
};
html! {
<div>
<button onclick={onincrease}>{ "Increase" }</button>
<button onclick={ondecrease}>{ "Decrease" }</button>
<button onclick={onincreaseby}>{ "Increase by 10" }</button>
<button onclick={ondecreaseby}>{ "Decrease by 10" }</button>
<button onclick={onset}>{ "Set to 100" }</button>
<button onclick={onreset}>{ "Reset" }</button>
<p>
<b>{ "Current value: " }</b>
{ *counter }
</p>
</div>
}
}The use_counter hook tracks the state of a number. It provides methods to manipulate the value, such as increase() and decrease(). To use it, import yew_hooks::prelude::* and call use_counter(initial_value) within a function component.
use yew_hooks::prelude::*;
#[function_component(Counter)]
fn counter() -> Html {
let counter = use_counter(0);
let onincrease = {
let counter = counter.clone();
Callback::from(move |_| counter.increase())
};
let ondecrease = {
let counter = counter.clone();
Callback::from(move |_| counter.decrease())
};
html! {
<>
<button onclick={onincrease}>{ "Increase" }</button>
<button onclick={ondecrease}>{ "Decrease" }</button>
<b>{ "Current value: " }</b>
{ *counter }
</>
}
}The use_websocket hook manages a WebSocket connection. It provides access to the connection's ready_state and a message stream. You can send messages using the .send() method. It is common to use use_effect_with to react to incoming messages from the ws.message field.
use yew::prelude::*;
use yew_hooks::prelude::*;
#[function_component(UseWebSocket)]
pub fn web_socket() -> Html {
let history = use_list(vec![]);
let ws = use_websocket("wss://echo.websocket.events/".to_string());
let onclick = {
let ws = ws.clone();
let history = history.clone();
Callback::from(move |_| {
let message = "Hello, world!".to_string();
ws.send(message.clone());
history.push(format!("[send]: {}", message));
})
};
// Reacting to incoming messages
{
let history = history.clone();
let ws = ws.clone();
use_effect_with(
ws.message,
move |message| {
if let Some(message) = &**message {
history.push(format!("[recv]: {}", message.clone()));
}
|| ()
},
);
}
html! {
<div>
<p>
<button {onclick} disabled={*ws.ready_state != UseWebSocketReadyState::Open}>{ "Send" }</button>
</p>
<p>
<b>{ "Message history: " }</b>
</p>
{
for history.current().iter().map(|message| {
html! {
<p>{ message }</p>
}
})
}
</div>
}
}The use_theme hook manages user theme preferences (dark or light mode). It persists the choice to localStorage using a provided key. If no preference is stored, it defaults to the system's prefers-color-scheme. It provides methods like .toggle() and .is_dark() to manage and check the current theme.
use yew::prelude::*;
use yew_hooks::prelude::*;
#[function_component(ThemeDemo)]
fn theme_demo() -> Html {
// Use a storage key for persistence across reloads/tabs
let theme = use_theme("example_theme".to_string());
let onclick = {
let theme = theme.clone();
Callback::from(move |_| theme.toggle())
};
html! {
<>
<button {onclick}>{ if theme.is_dark() { "Switch to light" } else { "Switch to dark" } }</button>
<p>{ format!("Active theme: {}", *theme) }</p>
</>
}
}The UseAsyncOptions struct allows you to configure the behavior of the use_async_with_options hook.
| Field | Type | Description |
|---|---|---|
auto | bool | If true, the async task runs automatically when the component mounts. |
Use UseAsyncOptions::enable_auto() as a shorthand to create options with auto: true.
Hooks to track browser and element properties:
use_window_size: tracks Window dimensions.use_window_scroll: tracks Window scroll position.use_scroll: tracks an HTML element's scroll position.use_scrolling: tracks whether HTML element is scrolling.use_infinite_scroll: infinite scrolling of the element.use_location: tracks browser's location value.use_hash: tracks browser's location hash value.use_search_param: tracks browser's location search param value.use_size: tracks an HTML element's dimensions using the ResizeObserver API.use_measure: tracks an HTML element's dimensions using the ResizeObserver API.use_geolocation: tracks user's geographic location.use_swipe: detects swipe based on TouchEvent.use_long_press: detects when a user presses and holds an element for a specified duration.use_visible: checks if an element is visible.use_hovered: checks if an element is hovered.use_permission: tracks browser's permission changes using the Permissions API.use_idle: tracks whether the user is idle (not interacting with the page).use_start_typing: triggers when user starts typing without an editable element focused.use_media_query: tracks if a CSS media query matches (e.g. screen size, dark mode).