介绍
组件是什么?
组件是 Yew 的基石。它们管理自己的状态,并可以渲染为 DOM。组件是通过实现描述组件生命周期的 Component
trait 来创建的。Component
trait 有许多方法需要被实现; 而 Yew 会在不同的生命周期调用这些方法。
生命周期
为我们的文档做出贡献:
添加组件的生命周期图示
生命周期方法
Create
当一个组件被创建时,它会从其父组件以及一个 ComponentLink
接收属性(properties)。属性(properties)可用于初始化组件的状态,“link”可用于注册回调或向组件发送消息。
通常将 props (可以通过这个在父子组件之间传递数据) 和 ComponentLink
存储在组件的结构体中,如下所示:
pub struct MyComponent {
props: Props,
link: ComponentLink<Self>,
}
impl Component for MyComponent {
type Properties = Props;
// ...
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
MyComponent { props, link }
}
// ...
}
View
组件在 view()
方法中声明它的布局。Yew 提供了 html!
宏来声明 HTML 和 SVG 节点和它们的监听器及其子组件。这个宏的行为很像 React 中的 JSX,但是使用的是 Rust 表达式而不是 JavaScript。
impl Component for MyComponent {
// ...
fn view(&self) -> Html {
let onclick = self.link.callback(|_| Msg::Click);
html! {
<button onclick=onclick>{ self.props.button_text }</button>
}
}
}
有关用法的详细信息,请查看 html!
宏指南。
Rendered
rendered
生命周期方法的调用时机是在:调用完view
并且 Yew 将结果渲染到 DOM ,而浏览器还未刷新页面的时候。当您想要执行只能在组件呈现元素后才能完成的操作时,此方法很有用。还有一个名为first_render
的参数可用于确定是否是在第一次渲染中调用此函数。
use stdweb::web::html_element::InputElement;
use stdweb::web::IHtmlElement;
use yew::prelude::*;
pub struct MyComponent {
node_ref: NodeRef,
}
impl Component for MyComponent {
// ...
fn view(&self) -> Html {
html! {
<input ref=self.node_ref.clone() type="text" />
}
}
fn rendered(&mut self, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.cast::<InputElement>() {
input.focus();
}
}
}
}
请注意,可以不实现此生命周期方法,默认情况下不会执行任何操作。
Update
组件是动态的,可以注册以接收异步信息。update()
生命周期方法对于每个消息都会被调用。这使得组件可以根据消息的内容来更新自身,并决定是否需要重新渲染自己。消息可以由 HTML 元素监听器触发,或者由子组件,Agents,Services 或 Futures 发送。
update()
可能看起来像下面这个例子:
pub enum Msg {
SetInputEnabled(bool)
}
impl Component for MyComponent {
type Message = Msg;
// ...
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::SetInputEnabled(enabled) => {
if self.input_enabled != enabled {
self.input_enabled = enabled;
true // 重新渲染
} else {
false
}
}
}
}
}
Change
组件可能被其父节点重新渲染。发生这种情况时,它们可以接收新的属性(properties)并选择重新渲染。这种设计通过更改属性(properties)来建立父子组件之间的通信。
一个典型的实现可能看起来像:
impl Component for MyComponent {
// ...
fn change(&mut self, props: Self::Properties) -> ShouldRender {
if self.props != props {
self.props = props;
true
} else {
false
}
}
}
Destroy
组件从 DOM 上被卸载后,Yew 调用 destroy()
生命周期方法来支持任何必要的清理操作。这个方法是可选的,默认情况下不执行任何操作。
关联类型
Component
trait 有两个关联类型:Message
和 Properties
。
impl Component for MyComponent {
type Message = Msg;
type Properties = Props;
// ...
}
Message
类型用于在事件发生后向组件发送消息;例如,您可能希望在用户单击按钮或向下滚动页面时执行某些操作。因为组件往往必须响应多个事件,所以Message
类型通常是一个枚举(enum),其中每个变量都是一个要处理的事件。
在组织代码库时,一个明智的做法是将Message
类型的定义写到其对应的组件模块中。此外最好是对消息类型采用一致的命名约定。有一种选择(虽然不是唯一的)是将类型命名为ComponentNameMsg
,例如,如果您的组件被称为Homepage
那么它的类型可以命名为HomepageMsg
。
enum Msg {
Click,
FormInput(String)
}
Properties
表示从父级传递到组件的信息。此类型必须实现 Properties
trait(通常通过派生),并且可以指定某些属性(properties)是必需的还是可选的。创建和更新组件时使用此类型。通常的做法是在组件模块中创建一个叫做 Props
的结构体并将其用作组件的 Properties
类型。通常将“properties”缩写为“props”。由于 props 是从父组件传递下来的,因此应用程序的根组件通常有一个类型为 ()
的 Properties
。如果你希望为根组件指定属性(properties),请使用 App::mount_with_props
方法。