fix(wd col picker): 修复列选择器自动补全和数据同步问题#1412
fix(wd col picker): 修复列选择器自动补全和数据同步问题#1412TAYUN wants to merge 2 commits intoMoonofweisheng:masterfrom
Conversation
改进自动补全逻辑,增加会话管理和序列控制防止重复触发 添加标签缓存优化性能,确保数据同步时显示正确 修复模型值变化时未正确更新显示列表的问题
添加loadingCount变量来跟踪并发加载请求,确保loading状态正确更新 使用深拷贝替代浅拷贝来避免数据引用问题
|
@TAYUN is attempting to deploy a commit to the weisheng's projects Team on Vercel. A member of the Team first needs to authorize it. |
✅ Deploy Preview for wot-design-uni ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
概览此变更为列选择器组件添加了自动完成机制和异步更新支持,通过引入加载计数、序列控制和标签缓存来追踪在途操作,防止过时更新,并用深拷贝替代浅拷贝以避免引用共享bug。 变更项
预估代码审查工作量🎯 3 (中等) | ⏱️ ~20 分钟 建议审查者
诗歌
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ 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.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue (1)
367-460: 防止resolve和finish回调重复调用导致的 loadingCount 双重递减。该函数通过 session 和 sequence 序列号防止过期操作的副作用,但未防止同一操作中用户代码同时调用
resolve和finish回调。根据 API 文档和示例(如if (areaData) { resolve(...) } else { finish() }),用户应仅调用其中之一,但代码未强制这一约束。若用户代码错误地同时调用两个回调,loadingCount会被双重递减,导致 loading 状态不准确。建议添加状态标志来防止重复调用:
resolve: (nextColumn: Record<string, any>[]) => { if (pickerSession !== session) return if (colChangeSeq[colIndex] !== seq) return + if (resolved || finished) return + resolved = true // ... rest }, finish: (isOk?: boolean) => { if (pickerSession !== session) return if (colChangeSeq[colIndex] !== seq) return + if (finished || resolved) return + finished = true // ... rest }其中
let resolved = false, finished = false在函数开始处声明。
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-11-24T06:12:44.418Z
Learnt from: Moonofweisheng
Repo: Moonofweisheng/wot-design-uni PR: 733
File: src/uni_modules/wot-design-uni/components/wd-tabs/wd-tabs.vue:327-327
Timestamp: 2024-11-24T06:12:44.418Z
Learning: 在 `src/uni_modules/wot-design-uni/components/wd-tabs/wd-tabs.vue` 中,由于 `title` 可能会发生变化,涉及到 `title` 的优化不太容易实现,需谨慎处理。
Applied to files:
src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue
📚 Learning: 2024-12-05T15:55:35.371Z
Learnt from: Moonofweisheng
Repo: Moonofweisheng/wot-design-uni PR: 761
File: src/uni_modules/wot-design-uni/components/wd-message-box/wd-message-box.vue:166-182
Timestamp: 2024-12-05T15:55:35.371Z
Learning: 在文件 `wd-message-box.vue` 的 `toggleModal` 方法中,当 `isPass` 为 `false` 时,应阻止执行 `confirm`,但不触发 `cancel` 操作。
Applied to files:
src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue
⏰ 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). (4)
- GitHub Check: Test Components (wd-col-picker)
- GitHub Check: Redirect rules - wot-design-uni
- GitHub Check: Header rules - wot-design-uni
- GitHub Check: Pages changed - wot-design-uni
🔇 Additional comments (10)
src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue (10)
106-106: 导入 isEqual 工具函数正确。该函数用于深度相等性比较,有助于准确检测 modelValue 的变化。
173-188: 使用 isEqual 进行深度比较可以避免不必要的更新。这个改进能够正确检测 modelValue 的实际变化,而不是仅仅依赖引用相等性。这样可以减少不必要的重新渲染和自动补全触发。
202-211: 缓存标签有助于提高显示一致性。在列数据变化时填充 labelCache 可以确保即使在异步数据加载过程中也能正确显示标签。类型守卫确保只缓存有效的键值对。
289-295: 会话管理机制能有效防止过期回调。通过递增
pickerSession并重置加载状态,这段代码确保了关闭选择器后,之前的异步操作不会影响新的会话。
333-337: 标签缓存回退提升了用户体验。当在当前 selectList 中找不到项目时,使用缓存的标签可以确保在数据异步加载期间仍然能显示有意义的文本。
340-365: 用户交互时正确取消自动补全操作。当用户手动选择项目时,重置
autoCompletePending和isCompleting标志,并递增序列号,确保之前的自动补全操作不会干扰用户的选择。同时缓存标签以供后续使用。
461-474: 确认时正确重置状态并使用浅拷贝发送数据。重置
loadingCount和其他状态变量确保了干净的状态。使用slice(0)创建浅拷贝来发送事件可以防止外部代码意外修改内部状态。
547-575: 自动补全逻辑重构提升了健壮性。新的实现正确处理了:
- 通过
isCompleting和autoCompletePending防止重入- 通过序列号防止过期操作
- 查找第一个缺失或不匹配的列
- 从缺失位置开始递归加载数据
这些改进有效解决了多级异步数据加载和 modelValue 变化时的同步问题。
注意:此逻辑依赖于
diffColumns中的递归,该函数存在 off-by-one 错误(已在其他评论中指出)。
135-135: 由于无法访问代码仓库,我无法直接验证关于labelCache的内存泄漏声明。为了提供准确的反馈,需要手动验证以下几点:
- 检查组件是否已有
onUnmounted钩子用于清理缓存- 确认
labelCache的使用方式和键值的生成逻辑- 验证缓存键的数量是否真的无限增长,还是有实际上界
- 查看是否存在其他的缓存大小限制机制
300-300: 改为使用项目已有的deepClone工具函数。项目的
util.ts已经提供了deepClone函数(第 500 行),支持循环引用处理。由于 uni-app 需要跨多个平台运行(H5、小程序、原生应用),而structuredClone在许多小程序引擎中并不可用,建议使用既存的deepClone工具函数,这样既能保证跨平台兼容性,又能获得更好的性能和对循环引用的支持。建议的修改:
在组件文件顶部导入
deepClone:import { deepClone } from '../common/util'然后替换:
- selectList.value = JSON.parse(JSON.stringify(lastSelectList.value)) + selectList.value = deepClone(lastSelectList.value)- lastSelectList.value = JSON.parse(JSON.stringify(selectList.value)) + lastSelectList.value = deepClone(selectList.value)Likely an incorrect or invalid review comment.
| if (nextIndex < modelValue.length - 1) { | ||
| diffColumns(nextIndex, seq) | ||
| return | ||
| } |
There was a problem hiding this comment.
递归停止条件存在 off-by-one 错误。
Line 536 的条件 nextIndex < modelValue.length - 1 会导致最后一列的子列数据不被加载。
例如,当 modelValue = [1, 2, 3] 时:
diffColumns(0)加载selectList[1](基于modelValue[0])diffColumns(1)加载selectList[2](基于modelValue[1])- 递归停止,但
selectList[3](基于modelValue[2])未被加载
这会导致用户看不到最后一个选择项之后的列,与用户手动点击的行为不一致。
🔎 建议的修复
if (seq !== autoCompleteSeq) return
const nextIndex = colIndex + 1
- if (nextIndex < modelValue.length - 1) {
+ if (nextIndex < modelValue.length) {
diffColumns(nextIndex, seq)
return
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (nextIndex < modelValue.length - 1) { | |
| diffColumns(nextIndex, seq) | |
| return | |
| } | |
| if (nextIndex < modelValue.length) { | |
| diffColumns(nextIndex, seq) | |
| return | |
| } |
🤖 Prompt for AI Agents
In src/uni_modules/wot-design-uni/components/wd-col-picker/wd-col-picker.vue
around lines 536-539, the recursive stop condition `nextIndex <
modelValue.length - 1` is off-by-one and prevents the last column's child data
from being loaded; change the condition to `nextIndex < modelValue.length` so
the recursion includes the final selected index's child column, then run the
component behavior/test to confirm the last column is loaded correctly after
selection.
🤔 这个 PR 的性质是?(至少选择一个)
🔗 相关 Issue
#704
#357
#264
修复背景
当前分支修复了 col-picker 在处理多级异步数据加载时, loading 状态显示不准确以及 modelValue 变更后数据自动补全(Auto Complete)逻辑的竞态问题。
解决方案
修复加载状态管理问题
在 handleColChange 中,使用 loadingCount 替代单纯的 boolean 值来管理 loading 状态。这解决了当存在多个并发的列数据请求时(例如快速切换列),前一个请求结束会错误地关闭 loading 动画,导致后续请求仍在进行但界面不再显示 loading 的问题。
确保在 columnChange 的 resolve 、 finish 回调以及 beforeConfirm 校验流程中,正确地增减 loadingCount ,保证加载状态的准确性。
修复自动补全与数据同步问题
重构了数据补全流程。当 modelValue 传入但对应的列数据缺失时,通过 diffColumns 递归调用 columnChange 来补齐缺失的列数据,确保深层级的数据能正确回显。
引入 autoCompletePending 和 isCompleting 标志位。如果在补全过程中 modelValue 再次发生变化,会将新的补全任务挂起,待当前任务结束后再次触发,防止数据状态错乱。
在 handleColChange 和 diffColumns 中增加了 seq (序列号) 校验,防止过期的异步回调覆盖最新的状态。
其他优化
优化了 getSelectedItem 方法,利用 labelCache 缓存已知的 value-label 映射,确保在数据列表尚未完全加载或临时缺失时,仍能尽可能正确地回显文本。
优化了对 modelValue 和 columns 的监听逻辑,减少不必要的重绘和计算。
风险:labelCache 内存泄漏风险
labelCache 的主要作用是 解决异步请求情况下的“回显”问题 。
代码中使用了一个 Map 来缓存 label:
这个 Cache 只要组件不销毁就会一直存在,并且:
建议 :应该考虑在组件销毁时清空,或者设置最大容量。虽然对于普通页面级组件可能影响不大,但对于长期运行的 SPA 应用是个隐患。
☑️ 请求合并前的自查清单
Summary by CodeRabbit
发布说明
✏️ Tip: You can customize this high-level summary in your review settings.