fix(tabs): a tab title that changes after the first render reaches the strip #12
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/tab-title-refresh"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The tab strip renders in the owner's (
Tabs') render pass, but aTab's updatedTitleonly lands when the Tab child re-renders — after the strip. So a live title, likeTagAuthoring's "Positive (n)" counts in Kagura, stayed one render stale: on a page that loads its document asynchronously, the badge stuck at "(0)" while three tags sat in the list, until some unrelated interaction happened to redraw the owner.A
Tabnow nudges its owner (Owner.Refresh()) fromOnParametersSetwhen itsTitlechanged. The nudge is self-terminating: the refresh re-renders the owner, the child re-renders with the same title, and no further refresh fires.Pinned by a test that renders a tab titled "Positive (0)", re-renders the parent with "Positive (3)", and asserts the strip button caught up — red without the fix, green with it (verified both ways). Full suite 288 green.
Found while browser-verifying Kagura's CG editor base mode, where the load produces exactly one re-render after the tags arrive — nothing ever corrected the strip.
🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagaku.UI - 95.1%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh my~ A Blazor render-ordering bug! The strip draws in the owner's pass, but the child's new
Titlelands after — so the badge sits one render stale, grinning at you with yesterday's news. What a sneaky little timing issue~ ♡ The fix is elegant: the child reaches up and taps the owner on the shoulder. "Excuse me, I changed~" Fufu~ I love it when a component knows how to ask for what it needs.Verdict: ✅ Looks good to me~
No blockers, no little ideas even. This is sharp work, scarlet~ Let me show you what I checked:
✅ What I liked~
Root-cause diagnosis is flawless.
Tabs.BuildRenderTreereadstab.Titlefrom the_tabscollection during the parent's render pass — but the child's[Parameter] Titleis only updated during Blazor's parameter-setting phase, which runs after the parent's tree is built. So the strip literally cannot see the new value without a nudge. The PR body's "TagAuthoring Positive (n)" story is exactly the shape of this bug — a page that loads async data and re-renders exactly once with the new count. Nothing else corrects the strip. Beautifully diagnosed~The
_ownerRenderedTitleshadow field is correct and self-terminating. On first render,OnInitializedseeds_ownerRenderedTitle = Title, soOnParametersSetsees equality → no spurious refresh. On a title change, the shadow ≠Title→Owner.Refresh()fires → owner re-renders → nextOnParametersSetsees equality → done. No render loop, no infinite ping-pong. I traced this through every arm~ ♡StateHasChanged()duringOnParametersSetis explicitly supported by Blazor. It queues a render after the current batch completes. Safe, idiomatic, no lifecycle violation.Multiple simultaneous title changes are safe. If N tabs change titles in one cycle, each calls
StateHasChanged— Blazor batches these into a single extra render. No N-render explosion.The test is genuinely directional, not a tautology. I traced the render pipeline: without the fix,
Tabs.BuildRenderTreedraws the strip fromtab.Title(still "Positive (0)") before the child's parameter update lands → the DOM shows "Positive (0)" →Assert.Contains("Positive (3)", ...)fails. With the fix,OnParametersSetnudges the owner → strip re-renders with the new value. The PR body's "verified both ways" claim holds up under scrutiny. And the comment inside the test explains why the bug exists, not just what it tests — that's the kind of test comment that survives future refactors~Consistent with the existing Tab↔Tabs coupling.
Register/Unregister/Refresh— all three are child-driven notifications through the[CascadingParameter] Owner. TheRefresh()addition sits naturally beside its siblings, and the XML doc on it is precise about why it exists (the render-ordering gap).Coverage confirms it. Tab: 100%/100% line/branch. The change-detected arm is exercised by the new test; the no-change arm is exercised by every other Tabs test (they all render tabs with stable titles). Tabs: 95.9%/84.4% — no regression.
Scope is exactly right. Only
Titleis tracked, notIconorId. Icons virtually never change at runtime, andIdchanges are rare (set once for URL slugs). Scoping to the actual bug — live title updates — is the correct call. No premature generalization~CI: forgejo-actions coverage bot #5740 present for head
7b5eda5(95.1%/88.7% overall). Local checks: skipped (CI green for current SHA).Automated review by Jibril · 2026-08-05
CI/CD: passed for head
7b5eda5· Local checks: skipped (CI green)