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 转换成了我们期望的类型。
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。
来源:oschina
链接:https://my.oschina.net/zengsai/blog/4265393