Yew 框架(二)子组件的创建和渲染

原创
2020/05/04 23:32
阅读数 5.7K

Yew 子组件的创建和渲染

前一篇 Yew框架(一) 应用初始化过程 我们了解一应用启动的过程,后续我将探索Yew中的一些功能是如何实现的,先来看看 子组件的创建渲染过程。

Yew 支持在组件的视图中嵌套组件,支持给子组件传递属性,下图是测试代码扩展前后的对比:

上面的代码主要是创建VChild对象,不是特别难,但要看懂它做了什么,为什么要这样做,还得先看 Properties 宏对组件的属性做了什么。

Properties 属性

这是我们自定义的Button组件的属性声明:

扩展后:

代码一下变多了。

首先是定义了一个 PropsWrapper,包含两个属性,但属性的类型都为Option类型,并且实现了Default特性,从后面的代码可以看到它就是PropsBuilder 用来存储过程信息的。

定义了两个结构体,都实现PropsBuilderStep特性,定义一个PropsBuilder结构体,有一个泛型参数,参数实现PropsBuilderStep。这是一个状态机在Rust的实现模式,用泛型参数来表示构建器的状态,通过构建器的方法来进行状态迁移,不同的状态可以调用不同的方法。

因为我们只有两个属性,所以 PropsBuilderStep 只有两个状态。PropsBuilderStep_missing_required_prop_text 是初始状态,该状态来可以调用 onclick 和 text 两个方法,来配置 builder,信息存储在 Builder 内部的 PropsWarpper 中。

值得注意的是,Yew 组件的属性是可以不传的,但可不可以不传是由属性的定义者来决定的,而不是调用者来决定的。如果定义一个属性为必传,那么调用者必须传入一个合适的值。如果定义为可不传,调用者可以决定传还是不传。Builder 中自动生成的方法参数上有区别,如果是可以不传的属性,其参数是Option类型。

为Props结构体实现 Properties 属性,只有一个builder方法,用来创建该属性的 Builder,最后由调用该Builder的build方法(该方法只能在 PropsBuilderStep_build 状态下调用,Builder的方法是逆序生成的,最后一个方法调用完成后进入 build 状态),用 PropsWrapper内存储的值来创建一个 Props 对象。

现在接着看 VChild 的创建。

创建 VChild 对象

VChild对象有一个泛型参数,是子组件的类型,这里是 Button。扩展后的创建代码如下:

调用 VChild::new() 方法,传入三个参数,第一个是通过构建器构建的组件属性,第二个是默认的 NodeRef, 第三个是 None。

从代码中看到构建方法的参数都用 VComp 的transform方法进行了转换,这是为何?

Transformer

从注释中得知这个特性功能是用来把属性(调用者传入的属性值)转换了期待的类型(子组件属性对象中对应属性期待的类型)。

VComp 实现多种类型转换,让父组件可以有多种传递属性给子组件的方式,简单说就是提供了“语法糖”。从 FROM 到 TO,表示当子组件的属性期待的是 TO 类型时,父组件可以为其提供 FROM 类型,由 Transformer 自动转换为 TO 类型,赋值给属性。

搜索源码,VComp一共有7个实现:

  • 子组件需要什么,父组件就传什么;
  • 当子组件需要 T 类型时,可以传入 &T,要求 T 具有 Clone 特性;
  • 如果子组件需要的是 String,父组件可以传入 &str;
  • 如果子组件需要的是 Option<T> 类型,父组件可以只传入 T 或 &T(要求 T 具有 Clone 特性)类型;
  • 如果子组件需要的是 Option<String> 类型,父组件可以传入 &str 或 Option<&str>。

在示例中,我们需要的是一个 String 类型和一个 Option<Callback<()>> 类型,父组件传入的是 &str 和 Callback<()> 类型。经过Transformer 转换成了我们期望的类型。

这个功能非常好用,之前学习另一个框架 simi 时,发现我希望传递给子组件的数据有时候是 Option<T>,有时候是T,有时候是 str,有时候是String,但它的子组件只能接收相同类型的值,在使用的时候要手动做转换,比较麻烦,代码写出来很不好看,当时想过为simi贡献一个补丁来解决这个问题,但一直没有找到合适的方案。这里 Transformer 利用Rust的自动类型推导和泛型能力很优雅的解决了这个问题,非常不错。

VChild::new()

这个方法很简单,就是创建一个 VChild 对象。

转化为 VComp

第一张图51行,表示最终会调用VNode::from方法:

内部先调用 VComp::from 方法将 VChild 转换为 VComp,最终转换为 VNode::VComp。

如此看来,VChild 也是一个备胎,它也只是在中途被用一下,在这里就被抛弃了,才创建出来没有两分钟,哈哈哈!重头在 VComp::new()

果然如此,代码长度说明一切!

Generator

用来根据 GeneratorType 渲染子组件视图并挂载到 Dom 的闭包。GeneratorType 有两种情况,一种是创建组件对象并挂载到节点,另一种是之前已经挂载过该组件对象了,只需要更新组件的属性。

闭包内的代码已经很熟悉了(参考 Yew框架(一) 应用初始化过程),第一种情况下,和挂载任意VNode类似,第二种情况下发出一个更新指令到调度器,会先更新组件Scope的状态(期间会调用组件的 change 方法)并重新渲染视图。

创建一个可以创建或更新子组件的闭包,但并未执行,将VComp置为 Unmounted的状态。在渲染视图时,会根据具体情况决定如何来渲染该VComp。

展开阅读全文
打赏
2
2 收藏
分享
加载中
请问一下,在yew_route里面创建了路由,通过button导航没有问题,但是在浏览器里直接输入,却报404找不到。
这是什么问题呢?
2020/07/27 11:24
回复
举报
曾赛博主
没有看到你的代码,根据描述可能是两个原因之一。 Yew的route在浏览器直接输入路径正常工作的前提有两个: 一是服务器端接收到路由相关的请求都当做是请求根目录/,返回内容是首页。 二是要在Web中监听History变化代码类似。 详细请看: ### How it works This library works by getting the url location from the browser and uses it to instantiate a type that implements Switch. Simply using `
<a rel="nofollow"></a>` tags to go to your route will not work out of the box, and are inefficient because the server will return the whole app bundle again at best, and at worst just return a 404 message if the server isn't configured properly. Using this library's RouteService, RouteAgent, RouterButton, and RouterLink to set the location via `history.push_state()` will change the route without retrieving the whole app again. #### Server configuration In order for an external link to your webapp to work, the server must be configured to return the `index.html` file for any GET request that would otherwise return a `404` for any conceivable client-side route. It can't be a `3xx` redirect to `index.html`, as that will change the
2020/07/27 23:58
回复
举报
谢谢答复。当时是我配置的问题,刷新以后,服务器会看请求的地址实际有没有文件,所以报的404
2020/07/28 17:52
回复
举报
不知道你有没有测试过 yew 的性能如何,比起 vue 等的性能如何
2020/05/06 17:43
回复
举报
曾赛博主
还没有。不过从技术上已经决定了可以做到比Vue更快,它是基于WebAssembly的。
2020/05/06 17:48
回复
举报
好了,已经找到解决办法了,
路由映射:
#[to = "/pages/index"] 必须在 #[to = "/"] 之前,
也就是说, #[to = "/"] 必须在最后,
现在没有问题了.
2020/05/05 21:13
回复
举报
曾赛博主
Yew 的路由模块最近有较大变化,可以先看看源码里的最新使用说明。
2020/05/06 10:07
回复
举报
求教,我用 yew 教程里的例子,一模一样,复制下来的代码,路由 web_logger 也加载正常,但就是路由不跳转, 怎么解决啊,有没有 yew 相关的群组啊
2020/05/05 17:36
回复
举报
曾赛博主
现在Yew团队从 std_web 转向 web_sys,不再推荐使用 web_logger,推荐使用 wasm_logger .
2020/05/06 10:09
回复
举报
更多评论
打赏
9 评论
2 收藏
2
分享
返回顶部
顶部