-
Notifications
You must be signed in to change notification settings - Fork 4.9k
fix(components-react): 修复 Input 组件受控模式下无法输入中文 #18731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough修改 Input 组件以引入局部状态 Changes
Sequence Diagram(s)sequenceDiagram
participant User as 用户
participant IME as 输入法编辑器
participant Input as Input 组件
participant DOM as DOM
User->>IME: 开始输入(非直接字符)
IME->>Input: compositionstart
Input->>Input: isOnComposition = true
User->>IME: 继续输入/修改
IME->>Input: compositionupdate
Input->>Input: 更新 compositionValue
Input->>DOM: 渲染 compositionValue(displayValue)
User->>IME: 确认/结束合成
IME->>Input: compositionend
Input->>Input: isOnComposition = false
Input->>Input: 调用 triggerValueChange(finalValue, e)
Input->>DOM: 更新真实 value 并触发 onInput 事件
代码审阅工作量🎯 4 (复杂) | ⏱️ ~45 分钟 建议审阅者
贺诗
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @packages/taro-components-react/src/components/input/index.tsx:
- Around line 144-173: The compositionend branch in handleComposition sets
this.onInputExecuted = true but relies on a subsequent handleInput to clear it,
which can fail in some WebViews; update handleComposition (compositionend
branch) to schedule a microtask fallback (e.g., Promise.resolve().then(...))
that clears this.onInputExecuted if it remains true after the event loop tick so
the flag cannot get stuck, keeping the existing immediate-true behavior for
normal browsers while ensuring eventual reset in environments that don't fire
the input event.
🧹 Nitpick comments (2)
packages/taro-components-react/src/components/input/index.tsx (2)
100-142:triggerValueChange修改 DOM 值时建议补一个更稳的边界与类型约束
目前仅对number做 maxlength 截断并回写e.target.value,整体 OK;但建议对maxlength <= 0、value非字符串(上游传入)做兜底,避免出现意外空串/异常。建议性改动(更稳的边界/类型兜底)
triggerValueChange (value: string, e: any) { @@ - let finalValue = value + let finalValue = value ?? '' + if (typeof finalValue !== 'string') finalValue = String(finalValue) const inputType = getTrueType(type, confirmType, password) @@ - if (inputType === 'number' && finalValue && maxlength <= finalValue.length) { + if (inputType === 'number' && maxlength > 0 && finalValue && maxlength <= finalValue.length) { finalValue = finalValue.substring(0, maxlength) // 如果被截断了,需要同步回 DOM if (e.target && e.target.value !== finalValue) { e.target.value = finalValue } }
238-265:compositionupdate里复用handleInput有副作用耦合,建议直接 setState(可选)
现在compositionupdate调handleInput会额外执行stopPropagation、以及受onInputExecuted早退逻辑影响;更直接的做法是在 compositionupdate 里只做setState({ compositionValue: e.target.value })。可选简化
} else if (e.type === 'compositionupdate') { // 拼音输入过程中,保持标记并更新显示 this.isOnComposition = true - // 必须在这里触发 setState 才能让输入框里的拼音实时更新 - this.handleInput(e) + // 直接更新显示值,避免复用 handleInput 带来的副作用耦合 + this.setState({ compositionValue: e.target.value }) } else if (e.type === 'compositionend') {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/taro-components-react/src/components/input/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build Rust Binding / stable - x86_64-pc-windows-msvc
🔇 Additional comments (2)
packages/taro-components-react/src/components/input/index.tsx (2)
40-69: 组合输入引入本地compositionValue状态的方向正确
这套“组合输入期间用内部 state 渲染、结束后再对外触发”的策略能对症解决受控模式下中文输入显示/上屏问题。
293-342:displayValue(compositionValue 优先)+ 绑定 onCompositionUpdate 的渲染路径合理
受控 value 在组合输入期间不再覆盖输入框显示,且补齐onCompositionUpdate,整体符合预期;另外 omit 掉onInput再由内部统一转发也能避免重复触发。
a592745 to
faf8d0c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/taro-components-react/src/components/input/index.tsx (1)
100-142: 注释与实现不一致,容易造成维护误解。第124行注释说明"只有当值确实改变,或者需要强制触发时才调用",但第125-141行的实现中,只要
typeof onInput === 'function'为真就直接调用onInput(e),没有任何值变更检查。该注释没有准确反映代码的实际行为,容易误导后续维护。
🧹 Nitpick comments (2)
packages/taro-components-react/src/components/input/index.tsx (2)
45-50: 注释顺序与代码实现不一致。第49行注释描述的操作顺序为
compositionend -> triggerValueChange(外部回调) -> onInputExecuted = true,但实际代码中(line 260-263)是先设置this.onInputExecuted = true再调用this.triggerValueChange()。建议修正注释以避免混淆:♻️ 建议的注释修正
-空格选词 (中文输入法): compositionend -> triggerValueChange(外部回调) -> onInputExecuted = true -> 紧随其后的 handleInput 被拦截退出。 +空格选词 (中文输入法): compositionend -> onInputExecuted = true -> triggerValueChange(外部回调) -> 紧随其后的 handleInput 被拦截退出。
144-173: handleInput 核心逻辑正确,但标志位使用可以优化。整体逻辑清晰地处理了 composition 期间和普通输入两种场景。不过在第163-171行有个小问题:
this.onInputExecuted = true // ... this.triggerValueChange(newValue, e) this.onInputExecuted = false这里将
onInputExecuted设为 true 后立即在同步调用triggerValueChange后重置为 false。由于triggerValueChange只是调用props.onInput回调,不太可能同步触发新的 input 事件,这个立即重置看起来是多余的。相比之下,
compositionend中设置该标志后不立即重置(line 260),而是依赖后续的handleInput调用来重置(line 149)。这种不一致可能引起维护困扰。建议考虑:
- 如果确认
triggerValueChange不会同步触发事件,可以移除 Case 2 中的标志位设置- 或者在注释中说明为什么需要这样处理
♻️ 简化建议(如确认不需要防护)
} else { // Case 2: 普通输入 (英文、数字、或中文选词后) - // 标记执行,防止重复 - this.onInputExecuted = true // 清理中间状态 if (this.state.compositionValue !== undefined) { this.setState({ compositionValue: undefined }) } this.triggerValueChange(newValue, e) - this.onInputExecuted = false }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/taro-components-react/src/components/input/index.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-06T06:55:44.077Z
Learnt from: Single-Dancer
Repo: NervJS/taro PR: 17653
File: packages/taro-components-advanced/src/components/water-flow/node.ts:83-95
Timestamp: 2025-05-06T06:55:44.077Z
Learning: 在 Taro 的 water-flow 组件中,getRectSizeSync 函数如果找不到指定的节点并且重试次数用尽,会一直处于 pending 状态而不是抛出错误,因为它在 retryTimes <= 0 时直接返回而不 resolve 或 reject Promise。应该使用 Promise.race 添加超时机制来解决这个问题。
Applied to files:
packages/taro-components-react/src/components/input/index.tsx
📚 Learning: 2025-05-06T06:55:44.077Z
Learnt from: Single-Dancer
Repo: NervJS/taro PR: 17653
File: packages/taro-components-advanced/src/components/water-flow/node.ts:83-95
Timestamp: 2025-05-06T06:55:44.077Z
Learning: 在 Taro 的 water-flow 组件中,getRectSizeSync 函数如果找不到指定的节点,会一直处于 pending 状态而不是抛出错误。在这种情况下,应该使用 Promise.race 添加超时机制,而不是仅依赖 try/catch 来处理错误。
Applied to files:
packages/taro-components-react/src/components/input/index.tsx
📚 Learning: 2025-05-06T06:55:44.077Z
Learnt from: Single-Dancer
Repo: NervJS/taro PR: 17653
File: packages/taro-components-advanced/src/components/water-flow/node.ts:83-95
Timestamp: 2025-05-06T06:55:44.077Z
Learning: 在 Taro 的 getRectSizeSync 函数中,如果找不到指定的节点,函数会一直处于 pending 状态而不是抛出错误。在这种情况下,使用 try/catch 处理不够充分,需要添加超时处理如 Promise.race 来避免无限等待。
Applied to files:
packages/taro-components-react/src/components/input/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Build Rust Binding / stable - x86_64-pc-windows-msvc
- GitHub Check: Build Rust Binding / stable - x86_64-unknown-linux-gnu
- GitHub Check: Build Rust Binding / stable - x86_64-apple-darwin
- GitHub Check: Build Rust Binding / stable - x86_64-unknown-linux-musl
- GitHub Check: Build Rust WASM / stable - wasm32-wasi
- GitHub Check: Build Rust Binding / stable - x86_64-pc-windows-msvc
- GitHub Check: Build Rust Binding / stable - x86_64-unknown-linux-musl
- GitHub Check: Build Rust Binding / stable - x86_64-unknown-linux-gnu
- GitHub Check: Build Rust WASM / stable - wasm32-wasi
🔇 Additional comments (5)
packages/taro-components-react/src/components/input/index.tsx (5)
40-42: 接口定义清晰。IState 接口设计合理,compositionValue 作为可选字段能够准确表示 IME 输入的临时状态。
53-69: 构造函数初始化正确。状态初始化和标志位设置合理,注释清晰说明了 onInputExecuted 的用途。
175-236: 事件处理器中的标志位重置合理。在
handlePaste、handleFocus和handleKeyDown中重置onInputExecuted标志,能够防止标志位异常保持导致后续输入被阻塞,这是防御性编程的良好实践。
280-344: 渲染逻辑正确实现了 IME 输入显示。关键改动:
- 从 state 中获取
compositionValue(line 293)- 计算
displayValue:优先显示compositionValue,否则显示受控的value(lines 313-315)- 将 input 的 value 绑定到
displayValue(line 332)- 添加
onCompositionUpdate事件处理(line 339)这个实现是整个方案的核心,正确地在 composition 期间显示 IME 中间输入(如拼音),在 composition 结束后显示最终值,完美解决了受控组件下中文输入的问题。
238-265: Composition 事件处理逻辑完全正确。该方法精妙地处理了 IME 输入的完整生命周期,通过
isOnComposition和onInputExecuted两个标记,完美适配 Chrome 和其他浏览器的事件顺序差异:
- compositionstart → compositionupdate → compositionend 的标准流程得到正确实现,compositionupdate 时通过 handleInput 只更新内部拼音显示状态,不向外触发 onChange
- 防重复触发机制在 compositionend 设置
onInputExecuted = true,后续 handleInput 中消费此标记,确保浏览器的 onChange 事件不会导致二次回调- 最终值通知通过 compositionend 中的 triggerValueChange 确保父组件收到最终汉字,而非拼音临时状态
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #18731 +/- ##
=======================================
Coverage 56.32% 56.32%
=======================================
Files 447 447
Lines 23345 23345
Branches 5795 5795
=======================================
Hits 13149 13149
- Misses 8366 8376 +10
+ Partials 1830 1820 -10
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
这个 PR 做了什么? (简要描述所做更改)
修复 Input 组件受控模式下无法输入中文
这个 PR 是什么类型? (至少选择一个)
这个 PR 涉及以下平台:
Summary by CodeRabbit
发布说明
Bug Fixes
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.