跳至主要内容
版本:0.21

生命周期

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(());
}
}

让我们了解一下这里发生的情况

  1. 使用 create 函数创建组件。
  2. 调用 view 方法,以便 Yew 知道要向浏览器 DOM 渲染什么。
  3. 调用 rendered 方法,该方法使用 Context 链接调度更新消息。
  4. Yew 完成后渲染阶段。
  5. Yew 检查预定的事件并查看更新消息队列是否为空,如果为空,则处理消息。
  6. 调用 update 方法,该方法返回 true 以指示已发生更改,并且组件需要重新渲染。
  7. 返回 2。

您仍可以在 rendered 方法中安排更新,并且这样做通常很有用,但请考虑在执行此操作时组件将如何终止此循环。

关联类型

Component 特征具有两种关联类型:MessageProperties

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。