Rust Yew应用开发的事件初探
在Rust的世界中有一个叫Yew的框架,它借鉴了React的思想。我的React代码也写了不少,今天就聊一下我个人对Yew应用开发中事件相关部分的体验。
我的也是才开始学习Rust和Yew,说得不对的地方还请大家多多指教。
下面的例子涉及到3个组件
ParentComponent组件
Button组件
<button/>原生html元素
也就是说,在ParentComponent组件中放置了Button组件,这个Button组件其实就是对<button/>的一个封装。这里的事件传递就是
<button/> -> Button -> ParentComponent
先从Button组件中的点击事件说起。
按钮事件定义如下
use yew::{Properties, Callback, MouseEvent};#[derive(Properties, PartialEq)]
pub struct Props {#[prop_or_default]pub onclick: Callback<MouseEvent>,
}
这里上面关于事件的onclick,虽然就2行代码,但这里面的信息量比较大,我将为大家逐一分析,以能知其所以然。
Properties
用于定义组件的参数,和React一样,当组件的参数更新时,Yew框架会自动更新组件。
在Yew框架中,通过结构体(struct)来定义组件的参数。在这个结构体中,你可以定义各种类型的字段,这些字段对应的就是组件的参数。
Properties本身是一个tarit,但并不需要我们开发人员来实现这个trait。Yew框架通过Rust的derive功能,自动将Properties的实现和你定义的结构体结合起来。
在结构体的字段中,就包含了我们要讨论的事件Callback。
也就是说,我们的事件就可以定义成下面这个样子。
#[derive(Properties)]
pub struct Props {pub onclick: Callback<()>,
}
PartialEq
和Properties一样,PartialEq也是一个trait,如果大家结合React的组件更新逻辑,估计能够猜得出来它的用意。是的,它就是Yew框架用来比较属性值,看其是否有更新。不过你完全不必担心自己忘记加上这个trait,因为编译器的错误报告会提醒你。这也是我喜欢Rust的地方。
Callback
用于定义组件暴露出来的事件。它的声明形式如下:
pub struct Callback<IN, OUT = ()> { /* private fields */ }
当我们定义一个空事件时,代码就是这样:
pub onclick: Callback<()>
在Yew应用开发中,通常用Callback<>来定义事件,因为Yew框架本身用Callback类型包装了html元素的事件。使用Callback类型来定义事件比较方便和安全。
prop_or_default
prop_or_default其实不是必须的。如果你不为你的字段添加这个attribute 宏,就必须在使用这个组件的地方为它设置值,否者会编译报错。这对组件的使用者来说显然不太友好。
因此,这里我们使用到了prop_or_default,它可以帮助Yew框架,在运行时,如果没有为事件字段赋值,系统会为其计算推导出默认值。
在Yew框架中,除了prop_or_default,还有prop_or(value)和prop_or_else(function)。
prop_or_default: 使用类型的默认值
prop_or(value): 使用给定的默认值
prop_or_else(function): 通过函数来获取默认值
MouseEvent
yew::MouseEvent实际上是从web_sys中导出的,它包含了鼠标当前的位置信息。具体可以参考https://docs.rs/web-sys/0.3.60/web_sys/struct.MouseEvent.html
之所以把MouseEvent提出来,是为了让大家对Yew中的Html的事件参数有一个初步的了解。
pub use web_sys::AnimationEvent;
pub use web_sys::DragEvent;
pub use web_sys::ErrorEvent;
pub use web_sys::Event;
pub use web_sys::FocusEvent;
pub use web_sys::InputEvent;
pub use web_sys::KeyboardEvent;
pub use web_sys::MouseEvent;
pub use web_sys::PointerEvent;
pub use web_sys::ProgressEvent;
pub use web_sys::SubmitEvent;
pub use web_sys::TouchEvent;
pub use web_sys::TransitionEvent;
pub use web_sys::UiEvent;
pub use web_sys::WheelEvent;
上面说了这么多关于Yew事件定义,接下来看看如何从原生的<button/> html元素上获取事件吧。
使用方式和React几乎是一样的,开发过React项目的同学是不是觉得很亲切啊。
<button style={danger_style} onclick={props.onclick.clone()}>{props.text.clone()}</button>
Button.rs的完整代码如下:
use yew::{function_component, html, Callback, Html, MouseEvent, Properties};#[derive(PartialEq)]
pub enum DisplayType {Default,Danger,
}#[derive(Properties, PartialEq)]
pub struct Props {#[prop_or_default]pub text: String,#[prop_or(DisplayType::Default)]pub display_type: DisplayType,#[prop_or_default]pub onclick: Callback<MouseEvent>,
}static default_style: &str = "..."; //隐藏不必要代码
static danger_style: &str = "..."; //隐藏不必要代码#[function_component]
pub fn Button(props: &Props) -> Html {match props.display_type {DisplayType::Danger => html! {<button style={danger_style} onclick={props.onclick.clone()}>{props.text.clone()}</button>},DisplayType::Default => html! {<button style={default_style} onclick={props.onclick.clone()}>{props.text.clone()}</button>},}
}
在上面的Button.rs中,我们创建了组件Button,并为其定义了事件onclick,下面就来看如何消费这个事件。
这里我想稍作停顿。我们知道Yew借鉴了React的思想,可以看到两者间很多的相似之处。但是毕竟Yew是基于Rust语言开发的,而React(这里特指ReactJs)是基于Javascript开发的。前者是静态编译语言,后者是动态语言。
因此,在Reat中,如何要处理Button中的onclick事件,代码应该像下面这个样子:
<Button onclick={()=>console.log('clicked')}/>
但是在Yew中,代码就没有简单了。
没关系,只要知其所以然,其实Yew中的事件处理也很简单。
在Yew应用开发中,处理事件的步骤如下:
- 定义事件枚举
- 将事件枚举绑定到要处理的组件事件上
- 在当前组件的update方法中处理事件
下面的代码用struct组件为例来展示如何处理Button上的onclick事件。
定义事件枚举
use yew::{ Component }
enum ParentComponentMsg {Toggle,
}pub struct ParentComponent;impl Component for ParentComponent {type Message = ParentComponentMsg;
}
在上面的代码中,按照Yew的惯例,将事件枚举的名称定义为"组件名称"+Msg,建议大家也遵守这个惯例。
然后不要忘记,对于初学者来说很容易忘记下面这行代码:
type Message = ParentComponentMsg;
这行代码是告诉编译器,ParentComponent使用的事件枚举的类型。如果没有这行代码,或者这行代码是"type Message = ();",在下一个步骤上,编译器会报错。
the trait `std::convert::From<components::base::parentComponent::ParentComponentMsg>` is not implemented for `()`
将事件枚举绑定到要处理的组件事件上
这里我们要处理Button组件的onclick事件,代码如下:
fn view(&self, ctx: &Context<Self>) -> Html {let onclick = ctx.link().callback(|_| ParentComponentMsg::Toggle);html! {<div class="modal"><Button text="点击" onclick={onclick}/></div>}}
上面的参数中,Context的出现频率很高,它用于获取当前组件的属性值,以及处理事件相关的处理。后面有机会再展开说说。
在当前组件的update方法中处理事件
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {match msg {ParentComponentMsg::Toggle => {log!("clicked");// 可以在这里修改self上的属性,即改变组件本身的状态,来触发新的渲染。这就是react的做法了。}}true}
让我再来夸夸Rust,它利用它的mut关键字来告诉编译器,这个对象是可修改的。如果没有mut关键字,但有修改对象属性的代码,编译器会直接报错。这一点在ReactJs中是做不到的。在ReactJs中,我们只能严格遵守只能通过setXXX来修改状态,但如果你鬼使神差地直接修改了状态值,一般情况下好像也没有报错(我不确定某些eslint插件是否具有这个功能)。
相比于ReactJs,要处理一个事件要多些这么多的代码,是有点不方便,但是如果你的代码写错了,编译器会报错,这里总算挽回了一点面子。
好了,关于《Rust Yew应用开发的事件初探》我就写在这里了。这真的是一个初探,里面的见解比较粗浅,因为我也是边学边用。我要去写我的项目去了,有什么新发现我再来和大家分享。
有不对的地方还请大家留言指教。
相关文章:
Rust Yew应用开发的事件初探
在Rust的世界中有一个叫Yew的框架,它借鉴了React的思想。我的React代码也写了不少,今天就聊一下我个人对Yew应用开发中事件相关部分的体验。 我的也是才开始学习Rust和Yew,说得不对的地方还请大家多多指教。 下面的例子涉及到3个组件 Paren…...
高并发下单例线程安全
1.使用静态内置类实现单例模式 自定义线程池 2.使用static代码块实现单例 3.使用静态内置类实现单例模式 4.使用static代码块实现单例 public class MySingleton {//使用volatile关键字保其可见性volatile private static MySingleton instance null;private MySingleton…...

【EKF】EKF原理
原理简述 卡尔曼滤波可以在线性模型,误差为高斯模型的情况下,对目标状态得出很好的估计效果,但如果系统存在非线性的因素,其效果就没有那么好了。比较典型的非线性函数关系包括平方关系,对数关系,指数关系…...
蓝桥杯官网填空题(古堡算式)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 福尔摩斯到某古堡探险,看到门上写着一个奇怪的算式:ABCDE ∗ ?EDCBA 他对华生说:“ABCDE 应该代表不同的数字,问号…...
Python---集合set
集合特点 1. 可以容纳多个数据 2. 可以容纳不同类型的数据 3.数据是无序存储的(不支持下标索引) 4. 不允许重复数据存在 5. 可以修改 6. 支持for循环,不支持while循环 集合定义 # 定义集合 变量 {元素1, 元素2, 元素3, 元素4...}# 定…...

LORA项目源码解读
大模型fineturn技术中类似于核武器的LORA,简单而又高效。其理论基础为:在将通用大模型迁移到具体专业领域时,仅需要对其高维参数的低秩子空间进行更新。基于该朴素的逻辑,LORA降低大模型的fineturn门槛,模型训练时不需…...

Azure + React + ASP.NET Core 项目笔记一:项目环境搭建(一)
不重要的目录标题 前提条件第一步:新建文件夹第二步:使用VS/ VS code/cmd 打开该文件夹第三步:安装依赖第四步:试运行react第五步:整理项目结构 前提条件 安装dotnet core sdk 安装Node.js npm 第一步:新…...

html 学习 之 文本标签
下面是一些常见的HTML文本标签(,,,,和)以及它们的作用: 标签 (Emphasis - 强调): 作用:用于在文本中表示强调或重要性。 示例: <p>这是一段文本,&l…...
联发科3纳米芯片预计2024年量产,此前称仍未获批给华为供货
9月7日,联发科与台积电共同宣布,联发科首款采用台积电3纳米制程生产的天玑旗舰芯片开发进度顺利,已成功流片,预计将在2024年量产,并将于下半年正式上市。这款旗舰芯片并非今年上市的天玑9300。 据联发科总经理陈冠州介…...

搭建vue3项目并git管理
搭建vue3项目 采用vue3的create-vue脚手架搭建项目,底层是vite,要求环境 node 16.0及以上(node -v检查node版本) 在文件夹右键->终端-> npm init vuelatest,输入项目名称,根据需要选择是否装包 src…...
【Azure OpenAI】OpenAI Function Calling 101
概述 本文是结合 github:OpenAI Function Calling 101在 Azure OpenAI 上的实现: Github Function Calling 101 如何将函数调用与 Azure OpenAI 服务配合使用 - Azure OpenAI Service 使用像ChatGPT这样的llm的困难之一是它们不产生结构化的数据输出…...

立晶半导体Cubic Lattice Inc 专攻音频ADC,音频DAC,音频CODEC,音频CLASS D等CL7016
概述: CL7016是一款高保真USB Type-C兼容音频编解码芯片。可以录制和回放有24比特音乐和声音。内置回放通路信号动态压缩, 最大42db录音通路增益,PDM数字麦克风,和立体声无需电容耳机驱动放大器。 5V单电源供电。兼容USB 2.0全速工…...
【Flutter】支持多平台 多端保存图片到本地相册 (兼容 Web端 移动端 android 保存到本地)
免责声明: 我只测试了Web端 和 Android端 可行哈 import dart:io; import package:flutter/services.dart; import package:http/http.dart as http; import package:universal_html/html.dart as html; import package:oktoast/oktoast.dart; import package:image_gallery_sa…...

postgresql 安装教程
postgresql 安装教程 本文以window 15版本为教程 文章目录 postgresql 安装教程1.下载地址2.以管理员身份运行3.选择安装路径,点击Next4.选择组件(默认都勾选),点击Next5.选择数据存储路径,点击Next6.设置超级用户的…...

手写数据库连接池
数据库连接是个耗时操作.对数据库连接的高效管理影响应用程序的性能指标. 数据库连接池正是针对这个问题提出来的. 数据库连接池负责分配,管理和释放数据库连接.它允许应用程序重复使用一个现有的数据路连接,而不需要每次重新建立一个新的连接,利用数据库连接池将明显提升对数…...
在CentOS7上增加swap空间
在CentOS7上增加swap空间 在CentOS7上增加swap空间,可以按照以下步骤进行操作: 使用以下命令检查当前swap使用情况: swapon --show创建一个新的swap文件。你可以根据需要指定大小。例如,要创建一个2GB的swap文件,使用…...

@Autowired和@Resource
文章目录 简介Autowired注解什么是Autowired注解Autowired注解的使用方式Autowired注解的优势和不足 Qualifier总结: Resource注解什么是Resource注解Resource注解的使用方式Resource注解的优势和不足 Autowired vs ResourceAutowired和Resource的区别为什么推荐使用…...

QTableView通过setColumnWidth设置了列宽无效的问题
在用到QT的QTableView时,为了显示效果,向手动的设置每一列的宽度,但是如下的代码是无效的。 ui->tableView->setColumnWidth(0,150);ui->tableView->setColumnWidth(1,150);ui->tableView->setColumnWidth(2,150);ui->t…...

【用unity实现100个游戏之10】复刻经典俄罗斯方块游戏
文章目录 前言开始项目网格生成Block方块脚本俄罗斯方块基类,绘制方块形状移动逻辑限制移动自由下落下落后设置对应风格为不可移动类型检查当前方块是否可以向指定方向移动旋转逻辑消除逻辑游戏结束逻辑怪物生成源码参考完结 前言 当今游戏产业中,经典游…...
Docker容器内数据备份到系统本地
Docker运行容器时没将目录映射出来,或者因docker容器内外数据不一致,导致docker运行错误的,可以使用以下步骤处理: 1.进入要备份的容器: docker exec -it <容器名称或ID> /bin/bash2.在容器内创建一个临时目录…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...