Skip to content

fix: 命令处理器在执行时读 props,不用组合期捕获的值 - #53

Merged
HarlonWang merged 1 commit into
mainfrom
fix/command-props
Oct 30, 2026
Merged

HarlonWang merged 1 commit into
mainfrom
fix/command-props

Conversation

@HarlonWang

@HarlonWang HarlonWang commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

问题

Sourcery 在 #52 上指出的老问题,与 #52 的改动无关:NodeScope.Commands 的处理器闭包里用的是组合期读到的 prop 值(TextField 的 maxLength、CodeField 的 length)。命令在它那批 flush 提交后送达,但早于这批引起的重组,所以同一批里既改了这个 prop 又发了用到它的命令时,处理器拿到的是上一次组合的值:

  • 一批里把 maxLength 4 改 10 并 setText("123456"),结果裁成 1234,onChange 也报 1234
  • CodeField 把 length 改大再 setText,同理

修复

处理器在执行时读 scope.get,不捕获组合期的值。scope.get 读的是节点 props 这个快照状态,主线程在快照外读到的就是最新提交值,#52 已保证命令晚于提交。只改 TextField.clip 与 CodeField.update 两处;LazyColumn.scrollTo 本来就现读 children.size。

规则写进 docs/components.md §4 和 Commands 的 KDoc:自定义组件的处理器照此办。

验证

  • 新增 CommandPropsTest(iosTest,compose.uiTest 只加在这个 source set,Android host 测试没有窗口):两条用例各在一批里改上限并 setText,断言 onChange 报完整的 123456。对着改动前的 Builtins.kt 跑,两条都失败,报 1234。
  • 本地 :compose:testAndroidHostTest、:compose:apiCheck、:compose:iosSimulatorArm64Test、:sample:shared:testAndroidHostTest、:sample:androidApp:assembleDebug 全部通过。公开 API 无变化。

🤖 Generated with Claude Code

Summary by Sourcery

Fix command handlers to use current props when processing commands that arrive before recomposition.

Bug Fixes:

  • Ensure TextField and CodeField commands use the latest prop values when updating text in the same flush as a prop change.

Enhancements:

  • Document that command handlers must read dependent props at execution time rather than using values captured during composition.

Build:

  • Add Compose UI test support to the iOS test source set.

Documentation:

  • Document command-handler prop-reading semantics for custom components.

Tests:

  • Add iOS tests covering same-flush TextField maxLength and CodeField length updates with setText commands.

命令在它那批 flush 提交后送达,但早于这批引起的重组:处理器若闭包了组合期读到的值,
同一批里改 prop 又发命令时就用了旧值。TextField.setText 的裁剪上限、CodeField.setText
的位数改为处理器里现读 scope.get。components.md §4 与 Commands 的 KDoc 写明这条规则。

新增 iOS 模拟器上的组合级测试(compose.uiTest,只加在 iosTest):同一批把上限 4 提到 10
并 setText("123456"),旧代码两条都裁成 1234。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Sorry @HarlonWang, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 3 days and 20 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@coderabbitai

coderabbitai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fae8abef-6b0f-442e-a3f6-83cd860669bc
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

本 PR 修复命令处理器捕获组合期 props 导致的陈旧值问题:TextField 和 CodeField 在命令执行时通过 NodeScope.get 读取最新限制,并以 iOS Compose UI 测试覆盖同一 flush 中的 prop 更新与 setText 场景,同时补充时序契约文档。

Sequence diagram for live props during command execution

sequenceDiagram
    participant Flush
    participant NodeScope
    participant Handler
    participant Recomposition

    Flush->>NodeScope: apply prop update
    Flush->>NodeScope: enqueue setText command
    NodeScope->>Handler: Commands consumes command
    Handler->>NodeScope: get(maxLength or length)
    NodeScope-->>Handler: latest committed prop
    Handler->>Handler: clip or update text
    Handler-->>NodeScope: dispatch onChange
    NodeScope->>Recomposition: schedule recomposition
Loading

File-Level Changes

Change Details Files
使命令处理器在执行时读取最新 props,避免同一 flush 中 prop 更新与命令同时到达时使用组合期旧值。
  • 将 TextField 的文本裁剪上限改为在命令处理路径中通过 scope.get 读取。
  • 将 CodeField 的长度限制改为在 update 执行时动态读取,并使用该值判断 onComplete。
  • 保留组合期读取的值仅用于响应式渲染和 LaunchedEffect,避免影响命令处理。
compose/src/commonMain/kotlin/app/tinyui/components/Builtins.kt
明确命令处理器的时序契约,并指导自定义组件采用执行期读取 props 的实现方式。
  • 补充 NodeScope.Commands KDoc,说明命令位于 flush 提交和后续重组之间执行。
  • 在组件文档中记录处理器不得捕获组合期 props,应在命令执行时调用 scope.get。
compose/src/commonMain/kotlin/app/tinyui/schema/NodeScope.kt
docs/components.md
新增跨平台 UI 测试,验证 prop 更新与 setText 同批提交时使用新限制值。
  • 新增 TextField 和 CodeField 两条 iOS Compose UI 测试,分别验证 maxLength 与 length 更新后命令不会使用旧值。
  • 为 iosTest source set 添加 compose.uiTest 依赖,适配 Android host 测试无窗口的限制。
compose/src/iosTest/kotlin/app/tinyui/components/CommandPropsTest.kt
compose/build.gradle.kts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codeseerbot codeseerbot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeSeer 审查

结论:批准

摘要

本次改动将 TextField 和 CodeField 的命令处理逻辑改为在执行时通过 scope.get 读取限制值,避免同一批 flush 更新 props 后仍使用上次组合期捕获值。新增的 iOS Compose UI 测试覆盖了两个受影响的 setText 场景,并补充了命令处理器的使用约束文档。基于给出的代码,未发现本次增量引入的可确认问题。

整个 PR 至 438ae85 · gpt-5.6-terra

@HarlonWang
HarlonWang merged commit 3170f12 into main Oct 30, 2026
5 checks passed
@HarlonWang
HarlonWang deleted the fix/command-props branch October 30, 2026 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant