2022抛弃js ,拥抱Yew框架(二) - 组件

11,136 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

组件

组件是 Yew 的基础。他们可以管理自己的状态并且也可以渲染他们自己的DOM.通过Component trait来实现,并且Component有许多需要是实现的方法;基本等同于前端React 的生命函数(钩子函数).在不同的阶段调用这些方法,别害怕这里钩子比React 的要简单很多.下面是生命周期图,在Yew 最新版本中推荐使用函数式组件,咱们后面也有讲到

image.png image.png

生命周期

create

组件创建时候,会从其父组件接收属性并存储在Context<Self>传递给create方法.属性可用于初始化组件状态和链接已经注册的回调或者给组件发送消息.

下面是官方demo

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有好的开发DOM的体验,Yew 提供了一个宏html!,用于HTML声明,SVG 节点(以及将属性和事件侦听器附加到它们)和一种方便的方式来呈现子组件.编码方式类似JSX 语法,并且提供了一些简写语法 例如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>
        }
    }
}

Rendered

rendered 生命函数,在View 触发之后已经渲染了组件,但是浏览器刷新之前.组件通常希望实现此方法以执行只能在组件渲染元素之后才能执行的操作。你可以通过 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

主要是判断根据消息处理,进行判断是不是更新当前组件.消息可以来自event listeners, child components, Agents, Services, or Futures

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 // 返回true 重新渲染
                } else {
                    false
                }
            }
        }
    }

    fn view(&self, _ctx: &Context<Self>) -> Html {
        html! {
            // impl
        }
    }
}

Changed

组件会根据父组件传递来的新属性重新渲染,简化了父子之间的通信.

Destroy

组件从DOM 卸载之后,Yew调用 destroy 方法,这个方法是可选的.默认情况下不执行任何操作。如果你想在组建销毁之前做清理操作,可以使用这个方法

源码地址