视图增量渲染
在视图模块最开始的设计上,我们的状态管理形式是直接全量更新Delta,然后使用EachLine遍历重建所有的状态。并且实际上我们维护了Delta与State两个数据模型,建立其关系映射关系本身也是一种损耗,渲染的时候的目标状态是Delta而非State。
这样的模型必然是耗费性能的,每次Apply的时候都需要全量更新文档并且再次遍历分割行状态。当然实际上只是计算迭代的话,实际上是不会太过于耗费性能,但是由于我们每次都是新的对象,那么在更新视图的时候,更容易造成性能的损耗,计算的性能通常可接受,而视图更新操作DOM成本更高。
实际上,我们上边复用其key值,解决的问题是避免整个行状态视图re-mount。而即使复用了key值,因为重建了整个State实例,React也会继续后边的re-render流程。因此我们在这里需要解决的问题是,如何在无变更的情况下尽可能避免其视图re-render。
由于我们实现了行级不可变状态维护,那么在视图中就可以直接对比状态对象的引用是否变化来决定是否需要重渲染。因此只需要对于ViewModel的节点补充了React.memo,在这个场景下甚至于不需要重写对比函数,只需要依赖我们的immutable状态复用能够正常起到效果。
同样的,针对LineView也需要补充memo,而且由于组件内本身可能存在状态变化,例如Composing组合输入的控制,所以针对于内部节点的计算也会采用useMemo来缓存结果,避免重复计算。
而视图刷新仍然还是直接控制lines这个状态的引用即可,相当于核心层的内容变化与视图层的重渲染,是直接依赖于事件模块通信就可以实现的。由于每次取lines状态时都是新的引用,所以React会认为状态发生了变化,从而触发重渲染。
而虽然触发了渲染,但是由于key以及memo的存在,会以line的状态为基准进行对比。只有LineState对象的引用发生了变化,LineModel视图才会触发更新逻辑,否则会复用原有的视图,这部分我们可以直接依赖React的devtools录制或Highlight就可以观察到。
视图增量更新这部分其实比较简单,主要是实现不可变对象以及key值维护的逻辑都在核心层实现,视图层主要是依赖其做计算,对比是否需要重渲染。其实类似的实现在低代码的场景中也可以应用,毕竟实际上富文本也就是相当于一个零代码的编辑器,只不过组装的不是组件而是文本。
总结
在先前我们主要讨论了视图层的适配器设计,主要是全量的视图初始化渲染,以及状态模型到DOM结构性的规则设定。在这里则主要考虑更新处理时性能的优化,主要是在增量更新时,如何最小化DOM以及Op操作、key值的维护、以及在React中实现增量渲染的方式。
其实接下来需要考虑输入内容时,如何避免规定的DOM的结构被破坏,主要涉及脏DOM检查、选区更新、渲染Hook等,这部分内容在#8和#9的输入法处理中已经有了详细的讨论,因此这里就不再次展开了。
patek-njs.watchjwd.cn
patek-cds.watchjwd.cn
patek-fss.watchjwd.cn
patek-xas.watchjwd.cn
patek-cqs.watchjwd.cn
patek-fss.watchjwb.cn
patek-cqs.watchjwb.cn
patek-tss.watchjwb.cn
patek-njs.watchgw.com
patek-sys.watchgw.com
patek-fss.watchgw.com
patek-njs.watchae.com
patek-fss.watchae.com
patek-gys.watchae.com
patek-cqs.watchae.com
patek-tss.watchae.com
patek-njs.ulysseshwx.com
patek-dls.ulysseshwx.com
patek-njs.szwatchpg.com
patek-sys.szwatchpg.com
patek-fss.szwatchpg.com
patek-gys.szwatchpg.com
patek-dls.szwatchpg.com
patek-fss.swatchstar.top
patek-dls.swatchstar.top
patek-yts.swatchstar.top
patek-njs.swatchkb.top
patek-sys.swatchkb.top
patek-fss.swatchkb.top
patek-njs.shrolexwatch.com
patek-fss.shrolexwatch.com
patek-dgs.shrolexwatch.com
patek-dls.shrolexwatch.com
patek-yts.shrolexwatch.com
patek-njs.shjshd.cn
patek-ncs.shjshd.cn
patek-njs.rogerweixiu.com
patek-sys.rogerweixiu.com
patek-zzs.rogerweixiu.com
patek-dgs.rogerweixiu.com
patek-ncs.rogerweixiu.com
patek-hzs.vay.net.cn
patek-sz.vay.net.cn
patek-xms.vay.net.cn
patek-bjs.watchshouhou.cn
patek-shs.watchshouhou.cn
patek-hzs.watchshouhou.cn
patek-bjs.jshdwatch.com
patek-hzs.jshdwatch.com
patek-njs.jshdwatch.com
那么接下来我们需要讨论的是编辑节点的组件预设,例如零宽字符、Embed节点、Void节点等。主要是为编辑器的插件扩展提供预设的组件,在这些组件内存在一些默认的行为,并且同样预设了部分DOM结构,以此来实现在规定范围内的编辑器操作。