解析QuickGrid内部实现:Defer组件的延迟渲染原理
Blazor渲染的基础逻辑
Blazor的渲染流程是同步的左序遍历,但组件渲染存在阶段区分:当父组件执行BuildRenderTree时,会依次处理所有子内容,但子组件的BuildRenderTree不会在父组件处理它的瞬间立即执行——Blazor会先将所有待渲染的组件节点加入渲染队列,待父组件自身渲染完成后,再按队列顺序执行子组件的渲染逻辑。
Defer组件的核心作用
QuickGrid需要先完成所有ColumnBase子组件的收集,再渲染表格主体。如果直接将表格主体与包含列的ChildContent放在同一层级,表格主体的渲染逻辑会与列的收集逻辑交织,导致列未收集完成就开始渲染表格。Defer的作用就是将表格主体的渲染推迟到所有列组件完成渲染(即列收集完成)之后。
Defer的实现原理
Defer本身是一个极简的ComponentBase子类,仅负责将传入的ChildContent添加到渲染树中,其核心逻辑完全依赖Blazor的渲染队列规则:
当QuickGrid执行自身
BuildRenderTree时,处理顺序为:- 调用
StartCollectingColumns()开启列收集会话 - 处理
@ChildContent:Blazor将其中所有ColumnBase组件加入渲染队列,但不立即执行它们的BuildRenderTree - 遇到
<Defer>组件:Blazor将Defer组件加入渲染队列,且排在之前所有ColumnBase组件之后
- 调用
当QuickGrid的
BuildRenderTree执行完毕后,Blazor开始处理渲染队列:- 先执行所有
ColumnBase组件的BuildRenderTree:每个列组件通过InternalGridContext.Grid.AddColumn(...)将自身加入列集合 - 所有列组件处理完成后,才会执行Defer组件的
BuildRenderTree:此时调用FinishCollectingColumns()结束收集,再渲染表格主体
- 先执行所有
为什么Defer能实现延迟?
你之前的误解在于:父组件处理子组件时,不会立即递归执行子组件的渲染逻辑,而是将子组件作为独立任务加入队列。父组件的BuildRenderTree是同步执行的,但子组件的渲染任务会在父组件自身渲染完成后,按队列顺序依次执行。
Defer作为独立组件,会被排在ChildContent内所有列组件的渲染任务之后,从而保证:
- 所有列组件的收集逻辑执行完毕
- 再触发表格主体的渲染流程
总结
Defer组件本身没有复杂逻辑,它只是利用了Blazor组件渲染队列的顺序规则:父组件中先出现的子组件会先被加入队列并优先执行渲染。通过将表格主体放在Defer内部,让其渲染任务滞后于所有列组件,最终实现了"先收集列、后渲染表格"的需求。
内容的提问来源于stack exchange,提问作者Sam

