版本信息 Link to heading
由于写此文时 dioxus 还在快速开发中,内部实现和功能相对不那么稳定。本文所述此针对 0.5
版本而言。
前言 Link to heading
dioxus 是一个类似于 react 的响应式框架。其中 hooks 主要用于状态的处理。在官方文档中提及 hook 的声名必需是有序的,框架会依这个顺序完成一些事情,并区分 hook。但并没有说为什么得是有序的。再加之给出的例子说明均是 signal 等,而这些本身又是智能针对(或者说是基于引用计数的共享指针),就会让人困惑:已经使用共享指针了,为什么还需要使用这个 hook 的顺序呢?这一指针不已经保证了唯一性了么?
Scope Link to heading
通过阅读源码,可以发现 use_hook
本身是对 runtime 的一个包装,里面核心的点在于 scope
与其中的 hook。
首先,我们要明白什么是 scope。这也是文档中未详细提及的。简单来说,就是每个 vnode 与 component 创建时,都会创建一个 scope。而 scope 就像栈与树一样会进行层级嵌套。每个 scope 会管理自己内部的 hook 及各种状态的生命周期。
什么是 hook Link to heading
hook 其实就是一个初始化的块,会在第一次声名时加入到对应的 scope 中,并进行执行。执行后返回的必定是一个 State
,而这个本身就是一个引用计算的智能指针。说白就是通过 scope 与 hook 来保证某一对象在相联的结点的生命周期内一定存活。
hook 设计的目的是针对 rerender 的。在 rerender 时,hook 并不会被重置执行,但由 hook 所产生的状态还存活,因此重新渲染时对应的数值就会被新的值所替换。
顺序 Link to heading
那么为什么 hook 要保证顺序呢?源码在 dioxus_core::scope_context::use_hook
。很简单,hook 创建时,为了避免重新加入,是通过当前 hooks 的数量与计算索引来判断的,只要当前索引小于计数就不会重新初始化。因此如果在条件分支等不确定因素下使用了 hooks,那么再重渲染时,就会破坏 hook 的次序,产生不可预计的结果,且有可能 hook 并没有被压入保存。同样,在取 hook 与使用时,也会受 scope 的层级、hook 数量产生影响。
异步、事件 Link to heading
拓展一下,这也是为什么官方例子中,所有的 use_resource
等都没有在事件触发的 closure 中,因为这些里面有 hook,要避免他们被不可控的初始化数量,与后续的行为。