61 个版本
0.3.2 | 2024年5月26日 |
---|---|
0.3.1 | 2024年3月5日 |
0.3.0 | 2023年10月3日 |
0.2.0 | 2022年11月25日 |
0.1.2 | 2021年12月25日 |
#95 in Web 编程
5,722 每月下载量
用于 11 个 crates(10 个直接使用)
215KB
4K SLoC
Yew Hooks
受 Yew、streamich/react-use、alibaba/hooks 和 vueuse/vueuse 启发的 Yew 的 Hooks。
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 }
</>
}
}
Hooks
状态
use_toggle
- 跟踪对应者的状态。use_bool_toggle
- 跟踪布尔值的状态。use_counter
- 跟踪数字的状态。use_latest
- 返回状态或 props 的最新不可变 ref。use_mut_latest
- 返回状态或 props 的最新可变 ref。use_previous
- 返回状态或 props 的上一个不可变 ref。use_list
- 跟踪列表的状态。use_map
- 跟踪哈希表的状态。use_set
- 跟踪哈希集的状态。use_queue
- 跟踪队列的状态。use_raf_state
- 创建只在requestAnimationFrame
之后更新的set
方法。use_state_ptr_eq
- 类似于use_state_eq
,但检查两个Rc
的值是否指向相同的分配。use_renders_count
- 计算组件渲染次数。use_default
- 当状态为 None 时返回默认值。use_debounce_state
- 节流状态。use_throttle_state
- 节流状态。
副作用
use_async
- 解析一个async
未来,例如获取 REST API。use_websocket
- 与WebSocket
通信。use_title
- 设置页面的标题。use_favicon
- 设置页面的 favicon。use_local_storage
- 管理在localStorage
中的值。use_session_storage
- 管理在sessionStorage
中的值。use_before_unload
- 当用户尝试重新加载或关闭页面时显示浏览器警告。use_debounce
- 防抖一个函数。use_debounce_effect
- 防抖一个效果。use_throttle
- 限制一个函数的执行频率。use_throttle_effect
- 限制一个效果的执行频率。use_clipboard
- 读取或写入剪贴板中的文本/字节。
生命周期
use_effect_once
- 修改过的 use_effect 钩子,只运行一次。use_effect_update
- 只在更新时运行效果。use_mount
- 调用挂载回调。use_unmount
- 调用卸载回调。use_is_first_mount
- 检查当前渲染是否为第一次。use_is_mounted
- 跟踪组件是否已挂载。use_event
- 订阅事件。use_logger
- 在组件通过生命周期时在控制台记录。
动画
use_timeout
- 安排一个超时来调用回调。use_interval
- 安排一个间隔来调用回调。use_update
- 返回一个回调,当被调用时重新渲染组件。use_raf
- 在每个requestAnimationFrame
上重新渲染组件。
传感器
use_window_size
- 跟踪窗口尺寸。use_window_scroll
- 跟踪窗口滚动位置。use_scroll
- 跟踪 HTML 元素的滚动位置。use_scrolling
- 跟踪 HTML 元素是否在滚动。use_infinite_scroll
- 元素的无限滚动。use_location
- 跟踪浏览器的位置值。use_hash
- 跟踪浏览器的位置哈希值。use_search_param
- 跟踪浏览器的位置搜索参数值。use_size
- 使用ResizeObserver
API 跟踪 HTML 元素的尺寸。use_measure
- 使用ResizeObserver
API 跟踪 HTML 元素的尺寸。use_geolocation
- 跟踪用户的地理位置。use_swipe
- 根据TouchEvent检测滑动。use_visible
- 检查一个元素是否可见。
UI
use_click_away
- 当用户点击目标元素外部时触发回调。use_drag
- 跟踪文件、链接和复制粘贴拖动,与use_drop
钩子一起使用。use_drop
- 跟踪文件、链接和复制粘贴的放置。use_media
- 播放视频或音频并公开其控件。
示例
use_counter
示例
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>
}
}
use_async
示例
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use yew::prelude::*;
use yew_hooks::prelude::*;
#[function_component(UseAsync)]
pub fn async_demo() -> Html {
let state = use_async(async move { fetch_repo("jetli/yew-hooks".to_string()).await });
let onclick = {
let state = state.clone();
Callback::from(move |_| {
// You can trigger to run in callback or use_effect.
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 }</b></p>
<p>{ "Repo full name: " }<b>{ &repo.full_name }</b></p>
<p>{ "Repo description: " }<b>{ &repo.description }</b></p>
<p>{ "Owner name: " }<b>{ &repo.owner.login }</b></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>
}
}
async fn fetch_repo(repo: String) -> Result<Repo, Error> {
fetch::<Repo>(format!("https://api.github.com/repos/{}", repo)).await
}
/// You can use reqwest or other crates to fetch your api.
async fn fetch<T>(url: String) -> Result<T, Error>
where
T: DeserializeOwned,
{
let response = reqwest::get(url).await;
if let Ok(data) = response {
if let Ok(repo) = data.json::<T>().await {
Ok(repo)
} else {
Err(Error::DeserializeError)
}
} else {
Err(Error::RequestError)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
struct User {
id: i32,
login: String,
avatar_url: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
struct Repo {
id: i32,
name: String,
full_name: String,
description: String,
owner: User,
}
// You can use thiserror to define your errors.
#[derive(Clone, Debug, PartialEq)]
enum Error {
RequestError,
DeserializeError,
// etc.
}
use_websocket
示例
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));
})
};
{
let history = history.clone();
let ws = ws.clone();
use_effect_with_deps(
move |message| {
if let Some(message) = &**message {
history.push(format!("[recv]: {}", message.clone()));
}
|| ()
},
ws.message,
);
}
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>
}
}
演示
贡献
欢迎查看此存储库中的当前问题,看看目前需要做什么。
如果您看到有什么缺失或可以改进的地方,也欢迎您打开一个 PR 或新问题。
许可
Apache-2.0/MIT
依赖
~11–15MB
~261K SLoC