生命周期
Component
特性具有多个需要实现的方法;Yew 将在组件生命周期的不同阶段调用这些方法。
生命周期
为我们的文档做出贡献:
添加组件生命周期的图表
生命周期方法
创建
当创建组件时,它会从其父组件接收属性,并存储在传递给 create
方法的 Context<Self>
中。这些属性可用于初始化组件的状态,而“链接”可用于注册回调或向组件发送消息。
use yew::{Component, Context, html, Html, Properties};
#[derive(PartialEq, Properties)]
pub struct Props;
pub struct MyComponent;
impl Component for MyComponent {
type Message = ();
type Properties = Props;
fn create(ctx: &Context<Self>) -> Self {
MyComponent
}
fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
// impl
}
}
}
视图
view
方法允许您描述如何将组件呈现到 DOM 中。使用 Rust 函数编写类似 HTML 的代码可能会变得非常混乱,因此 Yew 提供了一个名为 html!
的宏,用于声明 HTML 和 SVG 节点(以及为它们附加属性和事件侦听器),并提供了一种呈现子组件的便捷方式。该宏有点类似于 React 的 JSX(编程语言的差异除外)。一个区别是 Yew 提供了一个类似于 Svelte 的属性简写语法,其中您可以只写 {onclick}
,而不是写 onclick={onclick}
。
use yew::{Component, Context, html, Html, Properties};
enum Msg {
Click,
}
#[derive(PartialEq, Properties)]
struct Props {
button_text: String,
}
struct MyComponent;
impl Component for MyComponent {
type Message = Msg;
type Properties = Props;
fn create(_ctx: &Context<Self>) -> Self {
Self
}
fn view(&self, ctx: &Context<Self>) -> Html {
let onclick = ctx.link().callback(|_| Msg::Click);
html! {
<button {onclick}>{ &ctx.props().button_text }</button>
}
}
}
有关使用详情,请查看 html!
指南。
已呈现
在调用 view
且 Yew 将结果呈现到 DOM 中后,但浏览器刷新页面之前,将调用 rendered
组件生命周期方法。当您想要执行仅在组件呈现元素后才能完成的操作时,此方法很有用。还有一个名为 first_render
的参数,可用于确定此函数是在首次呈现时调用,还是在后续呈现时调用。
use web_sys::HtmlInputElement;
use yew::{
Component, Context, html, Html, NodeRef,
};
pub struct MyComponent {
node_ref: NodeRef,
}
impl Component for MyComponent {
type Message = ();
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {
node_ref: NodeRef::default(),
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<input ref={self.node_ref.clone()} type="text" />
}
}
fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {
input.focus();
}
}
}
}
请注意,此生命周期方法不需要实现,并且默认情况下不执行任何操作。
更新
与组件的通信主要通过消息进行,而消息由 update
生命周期方法处理。这允许组件根据消息内容更新自身,并确定是否需要重新渲染自身。消息可以通过事件侦听器、子组件、代理、服务或期货发送。
以下是 update
实现示例
use yew::{Component, Context, html, Html};
pub enum Msg {
SetInputEnabled(bool)
}
struct MyComponent {
input_enabled: bool,
}
impl Component for MyComponent {
type Message = Msg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {
input_enabled: false,
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::SetInputEnabled(enabled) => {
if self.input_enabled != enabled {
self.input_enabled = enabled;
true // Re-render
} else {
false
}
}
}
}
fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
// impl
}
}
}
已更改
组件可以由其父组件重新渲染。发生这种情况时,它们可能会收到新属性并需要重新渲染。此设计通过仅更改属性值来促进父组件到子组件的通信。有一个默认实现,在属性更改时重新渲染组件。
销毁
在组件从 DOM 卸载后,Yew 调用 destroy
生命周期方法;如果您需要在组件被销毁之前执行操作以清理组件的早期操作,则需要此方法。此方法是可选的,并且默认情况下不执行任何操作。
无限循环
使用 Yew 的生命周期方法可能会出现无限循环,但仅当在每次渲染后尝试更新同一组件时才会出现,而该更新也会请求渲染组件时才会出现。
下面可以看到一个简单的示例
use yew::{Context, Component, Html};
struct Comp;
impl Component for Comp {
type Message = ();
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self
}
fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
// We are going to always request to re-render on any msg
true
}
fn view(&self, _ctx: &Context<Self>) -> Html {
// For this example it doesn't matter what is rendered
Html::default()
}
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
// Request that the component is updated with this new msg
ctx.link().send_message(());
}
}
让我们了解一下这里发生的情况
- 使用
create
函数创建组件。 - 调用
view
方法,以便 Yew 知道要向浏览器 DOM 渲染什么。 - 调用
rendered
方法,该方法使用Context
链接调度更新消息。 - Yew 完成后渲染阶段。
- Yew 检查预定的事件并查看更新消息队列是否为空,如果为空,则处理消息。
- 调用
update
方法,该方法返回true
以指示已发生更改,并且组件需要重新渲染。 - 返回 2。
您仍可以在 rendered
方法中安排更新,并且这样做通常很有用,但请考虑在执行此操作时组件将如何终止此循环。
关联类型
Component
特征具有两种关联类型:Message
和 Properties
。
impl Component for MyComponent {
type Message = Msg;
type Properties = Props;
// ...
}
Message
类型用于在事件发生后向组件发送消息;例如,您可能希望在用户单击按钮或向下滚动页面时执行某些操作。由于组件往往必须响应多个事件,因此 Message
类型通常是一个枚举,其中每个变体都是要处理的事件。
在组织代码库时,将 Message
类型的定义包含在定义组件的同一模块中是明智的。您可能会发现采用一致的命名约定来命名消息类型很有帮助。一种选择(但不是唯一选择)是将类型命名为 ComponentNameMsg
,例如,如果您的组件称为 Homepage
,则可以将类型称为 HomepageMsg
。
enum Msg {
Click,
FormInput(String)
}
Properties
表示从其父级传递给组件的信息。此类型必须实现 Properties
特征(通常通过派生它),并且可以指定某些属性是必需的还是可选的。此类型在创建和更新组件时使用。通常的做法是在组件的模块中创建一个名为 Props
的结构,并将其用作组件的 Properties
类型。通常将“properties”缩写为“props”。由于 props 是从父组件传递下来的,因此应用程序的根组件通常具有 ()
类型的 Properties
。如果您希望为根组件指定属性,请使用 App::mount_with_props
方法。
生命周期上下文
所有组件生命周期方法都采用上下文对象。此对象提供对组件范围的引用,该引用允许向组件发送消息和传递给组件的 props。