-
Notifications
You must be signed in to change notification settings - Fork 272
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
refactor: cascader #3007
base: feat_v3.x
Are you sure you want to change the base?
refactor: cascader #3007
Conversation
Warning Rate limit exceeded@oasis-cloud has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 49 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (15)
Walkthrough此次变更主要集中在 Cascader 组件及其测试、demo、文档、类型定义和工具函数的重构与优化。测试文件中删除了与 Tree 类相关的逻辑,组件文件调整了属性和方法签名,引入了异步加载选项的处理,同时 demo 示例和相关文档也做了对应调整。部分状态管理命名统一为 visible、value 和 options,工具函数重命名为 normalizeOptions/normalizeListOptions,并添加了新的工具方法 isEmpty。 Changes
Sequence Diagram(s)sequenceDiagram
participant U as 用户
participant C as Cascader组件
participant A as 异步onLoad函数
U->>C: 选择一个选项
C->>A: 调用onLoad(选项, level)
A-->>C: 返回Promise及子选项数据
C->>C: 更新状态与选项数据
U->>C: 触发onChange确认选择
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 4
🔭 Outside diff range comments (3)
src/packages/cascader/demos/h5/demo6.tsx (1)
89-94
: 🛠️ Refactor suggestion建议改进事件处理函数的类型安全性
事件处理函数使用了
any
类型,这降低了代码的类型安全性。- const onChange = (value: any, path: any) => { + const onChange = (value: CascaderOption['value'][], path: CascaderOption[]) => { setValue(value) } - const onPathChange = (value: any, path: any) => { + const onPathChange = (value: CascaderOption['value'][], path: CascaderOption[]) => { console.log('onPathChange', value, path) }src/packages/cascader/demos/taro/demo4.tsx (1)
1-70
: 🛠️ Refactor suggestion建议提取共享逻辑
此文件与 h5/demo4.tsx 存在大量重复代码。建议提取共享逻辑到一个公共文件中,减少代码重复。
建议:
- 创建一个共享的 hooks 文件
- 将状态管理和异步加载逻辑移至该文件
- 在 H5 和 Taro 版本中复用该逻辑
示例实现:
// hooks/useCascaderDemo.ts export function useCascaderDemo() { const [visible, setVisible] = useState(false) const [value, setValue] = useState<string[]>([]) const [options, setOptions] = useState<CascaderOption[]>([]) useEffect(() => { // 初始化逻辑 }, []) const lazyLoad = async (node: CascaderOption, level: number) => { // 异步加载逻辑 } return { visible, setVisible, value, setValue, options, lazyLoad, } }src/packages/cascader/__tests__/cascader.spec.tsx (1)
142-143
: 💡 Verification agent🧩 Analysis chain
快照测试需要更新
测试用例的快照不匹配,这可能是由于组件的有意更改导致的。请检查更改是否符合预期,然后更新快照。
运行以下命令更新快照:
🏁 Script executed:
#!/bin/bash # 更新失败的快照测试 npm test -- -uLength of output: 867
快照更新失败:配置问题需要解决
目前快照测试因预期的组件更改而不匹配,但在执行更新快照命令时(
npm test -- -u
)出现了配置错误——在加载vite.config.mts
时缺少依赖@vitejs/plugin-react
。请按以下步骤操作:
- 确认组件更改:确认快照不匹配是预期的变更结果。
- 检查并修复依赖配置:请检查项目的 Vite 配置文件以及相关依赖项,确保已正确安装
@vitejs/plugin-react
或调整配置以匹配当前项目需要。- 重新更新快照:配置问题解决后,再次运行
npm test -- -u
来更新快照。涉及文件:
src/packages/cascader/__tests__/cascader.spec.tsx
(第142-143行处)vite.config.mts
(配置文件中涉及依赖的加载)🧰 Tools
🪛 GitHub Actions: CI
[error] 143-143: Snapshot
Cascader > visible true 1
mismatched
🧹 Nitpick comments (33)
src/packages/cascader/demos/h5/demo6.tsx (2)
19-21
: 建议改进 value 状态的类型定义当前 value 的类型定义为
string[]
,建议使用更具体的类型来增强类型安全性。- const [value, setValue] = useState<string[]>(['浙江', '温州', '鹿城区']) + const [value, setValue] = useState<CascaderOption['value'][]>(['浙江', '温州', '鹿城区'])
22-88
: 建议添加加载状态管理异步加载数据时没有处理加载状态,可能会影响用户体验。建议添加 loading 状态来优化交互。
+ const [loading, setLoading] = useState(true) useEffect(() => { + setLoading(true) setTimeout(() => { setOptions([ // ... options ... ]) + setLoading(false) }, 300) }, [])然后在 Cascader 组件中使用:
<Cascader visible={visible} activeColor="#3768FA" value={value} title="选择地址" options={options} + loading={loading} // ... other props ... />
src/packages/cascader/demos/taro/demo2.tsx (1)
75-77
: 建议改进类型定义
onChange
处理函数存在以下问题:
- 使用了
any
类型,降低了类型安全性path
参数未被使用,但仍被声明建议按如下方式优化:
- const onChange = (value: any, path: any) => { + const onChange = (value: string[]) => { setValue(value) }src/packages/cascader/utils.ts (1)
3-22
: 递归地规范化选项结构时,应注意对 children 的类型检查。
当前对children
的处理默认假设其为数组,若后续外部传参出现非数组类型,可能导致normalizeOptions
抛出错误。可在递归调用前确保对children
进行判空或类型判断,以增强健壮性。- children: normalizeOptions(children, keyMap), + children: Array.isArray(children) + ? normalizeOptions(children, keyMap) + : undefined,src/packages/cascader/demos/h5/demo1.tsx (3)
5-11
: 使用 State 管理visible
、value
、options
与回调函数onChange
。
命名清晰,逻辑简洁。但若有异步需求,可在onChange
内部添加防抖或节流逻辑,以应对频繁操作。
12-77
: 通过定时器模拟异步设置 options 的做法缺少错误处理。
在真实环境中或需调用接口获取数据,可额外捕获错误或取消请求。若只做演示,可在注释中标明示例用途,方便后期维护。
83-85
:Cell
的description
字段与新状态value
对应正确。
若value
存在多级选中,可考虑在 UI 上进行拼接或展示完整层级路径,提高易用性。src/packages/cascader/cascader.tsx (4)
2-18
: React Hooks 与组件依赖的引入顺序清晰。
这里引入了部分 NutUI 图标组件与内部自定义 Hook,建议定期审视依赖关系,若有重复引用或未使用的依赖应及时清理。
55-74
:CascaderProps
接口新增与合并的字段较多,注意字段含义和可选性的一致性。
onLoad
、onChange
、onPathChange
等返回值、参数类型都需要与真实使用场景相符,否则可能引起调用端类型断言失效或业务逻辑混乱。
76-92
:defaultProps
使用类型断言时需注意与接口字段保持一致。
如果后续对CascaderProps
有更新,应同步修正这里的默认值,否则会增大维护成本。
266-343
: 渲染级联条目与 Tabs 切换部分在交互可用性上值得优化。
renderCascaderItem
中针对disabled
、active
、loading
设置了较好的状态区分。- 如需在移动端适配,可在 className 或样式上增加更细的触控区域提示。
- Popup 关闭前,可添加一些过渡动画或二次确认逻辑(根据业务场景),并与 Tabs 的切换逻辑保持一致。
src/packages/cascader/cascader.taro.tsx (4)
2-14
: 简化组件依赖的导入顺序有助于阅读与维护。
组件依赖较为分散,建议在后续合并或归类导入,以提高可维护性。
55-74
: CascaderProps 接口拓展,支持更多自定义回调与弹窗配置。
onLoad
、onChange
、onPathChange
、onTabsChange
函数签名明确,提高可扩展性。- 建议为
value
、defaultValue
、visible
等属性添加更详细的 JSDoc 注释,提高团队协作时的可理解度。
236-264
:chooseItem
异步加载分支完善,需检查竞态与错误处理。
- 当
onLoad
调用返回较慢或发生异常时,当前逻辑仅在try/catch
之后简单打印错误或置空loading
,可考虑增加更多提示或重试机制。- 对比
pane.leaf
与pane.children
的判断逻辑,如后续出现伪空数据或字段缺失,可能出现意外分支。
324-343
: 切换是否显示 Popup 的条件式渲染处理直观,注意控制底层动画与交互一致。
- 建议在
Popup
关闭后回调里能清楚区分点击遮罩与点击关闭图标等情况,以便进行更丰富的业务处理。src/utils/is-empty.ts (1)
1-6
:isEmpty
工具函数实现简洁,请谨慎处理特殊类型边界。
例如:若传入new Date()
、NaN
、或类似无可枚举属性的对象,需要防范意外判定。可考虑补充更多单元测试覆盖场景。src/packages/cascader/types.ts (2)
15-16
: 使用索引签名[key: string]: any
扩展CascaderOption
的灵活性。
在不一致的团队协作环境下,需明确约定可能添加的额外字段含义,避免导致数据结构不规范。
40-43
: 新增CascaderActions
类型,开放open()
与close()
方法。
该设计便于父级组件或外部管理弹窗状态,但可考虑是否需要更多状态同步回调来满足复杂业务场景。src/packages/cascader/demos/h5/demo3.tsx (2)
25-27
: 建议改进 onChange 的类型定义当前 onChange 的参数使用了 any 类型,建议使用更具体的类型定义以提高类型安全性。
- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) }
8-24
: 优化异步加载逻辑loadCascaderItemData 函数有以下几点建议:
- 将 500ms 的延迟时间提取为常量
- leaf 判断条件 (level >= 2) 建议添加注释说明原因
+ const LOAD_DELAY = 500 const loadCascaderItemData = ( node: CascaderOption, level: number ): Promise<CascaderOption[]> => { return new Promise((resolve) => { - setTimeout(() => { + setTimeout(() => { const { value } = node const text = value?.toString().substring(0, 1) const value1 = `${text}${level + 1}1` const value2 = `${text}${level + 1}2` resolve([ + // 当层级达到2时设置为叶子节点 { value: value1, text: value1, leaf: level >= 2 }, { value: value2, text: value2, leaf: level >= 2 }, ]) - }, 500) + }, LOAD_DELAY) }) }src/packages/cascader/demos/taro/demo3.tsx (1)
25-27
: 建议改进 onChange 的类型定义与 H5 版本相同,建议改进类型定义以提高代码质量。
- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) }src/packages/cascader/demos/h5/demo5.tsx (2)
14-27
: 建议优化初始化逻辑useEffect 中的延迟初始化有以下建议:
- 将 300ms 延迟时间提取为常量
- 考虑添加加载状态指示器
- 建议添加错误处理机制
+ const INIT_DELAY = 300 + const [loading, setLoading] = useState(false) useEffect(() => { + setLoading(true) setTimeout(() => { setValue(['广东省', '广州市']) setOptions([ // ... options ]) + setLoading(false) - }, 300) + }, INIT_DELAY) }, [])
29-31
: 改进 onChange 的类型安全性建议使用更具体的类型定义替代 any。
- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) }src/packages/cascader/demos/h5/demo4.tsx (2)
25-28
: 建议改进类型注解
node: any
的类型注解过于宽松,建议使用更具体的类型。- node: any, + node: CascaderOption,
42-44
: 建议补充类型注解
change4
函数的参数类型应该更明确。- const change4 = (value: any, path: any) => { + const change4 = (value: string[], path: CascaderOption[]) => {src/packages/cascader/demos/taro/demo1.tsx (2)
8-10
: 建议改进类型安全性建议为
onChange
函数参数添加更具体的类型定义,避免使用any
。- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) }
11-77
: 建议优化异步加载逻辑
- 建议将超时时间抽取为常量或配置项
- 建议添加错误处理和加载状态
+ const [loading, setLoading] = useState(false) + const LOAD_TIMEOUT = 300 useEffect(() => { + setLoading(true) setTimeout(() => { setOptions([...]) + setLoading(false) - }, 300) + }, LOAD_TIMEOUT) + return () => setLoading(false) }, [])src/packages/cascader/demos/h5/demo7.tsx (2)
8-11
: 建议移除生产环境的调试代码建议移除
console.log
语句,或使用环境变量控制调试输出。const onChange = (value: any, path: any) => { - console.log('onchange', value, path) setValue(value) } // ... onPathChange={(value, path) => { - console.log(value, path) }}Also applies to: 102-104
15-77
: 建议抽取共享的选项数据建议将重复的选项数据抽取到共享的配置文件中。
+// cascaderOptions.ts +export const defaultOptions = [ + { + value: '浙江', + text: '浙江', + children: [...] + }, + // ... +] // demo7.tsx +import { defaultOptions } from './cascaderOptions' useEffect(() => { setTimeout(() => { - setOptions([...]) + setOptions(defaultOptions) }, 300) }, [])src/packages/cascader/demos/taro/demo6.tsx (2)
22-88
: 建议将超时时间提取为常量建议将 useEffect 中的超时时间 300 提取为一个有意义的常量,以提高代码的可维护性。
+ const LOADING_DELAY = 300 useEffect(() => { setTimeout(() => { setOptions([ // ...options - ], 300) + ], LOADING_DELAY) }, [])
89-91
: 建议添加类型注解onChange 处理函数的参数类型应该更明确。
- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => {src/packages/cascader/doc.zh-TW.md (1)
45-46
: 建议改进繁体中文表述建议将"透過"改为"通過",使表述更符合繁体中文的使用习惯。
- Cascader 內部透過 `value` 和 `onLoad` 實作了自動載入資料的邏輯 + Cascader 內部通過 `value` 和 `onLoad` 實作了自動載入資料的邏輯🧰 Tools
🪛 LanguageTool
[uncategorized] ~45-~45: 您的意思是“"不"透”?
Context: ...## 動態加載lazy
屬性表示開啟資料的自動加載,Cascader 內部透過value
和onLoad
實作了自動載入資料的邏輯。 `laz...(BU)
src/packages/cascader/doc.en-US.md (1)
23-27
: 新增 Uncontrolled 示例说明
新增的“Basic Usage - Uncontroled”部分展示了组件在非受控模式下的用法,建议修正标题中的拼写错误(“Uncontroled” → “Uncontrolled”),以保证英文表达的准确性。提供修改建议:
-### Basic Usage - Uncontroled +### Basic Usage - Uncontrolled
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/packages/cascader/__tests__/__snapshots__/cascader.spec.tsx.snap
is excluded by!**/*.snap
📒 Files selected for processing (26)
src/packages/cascader/__tests__/cascader.spec.tsx
(4 hunks)src/packages/cascader/cascader.taro.tsx
(1 hunks)src/packages/cascader/cascader.tsx
(1 hunks)src/packages/cascader/demo.taro.tsx
(1 hunks)src/packages/cascader/demo.tsx
(3 hunks)src/packages/cascader/demos/h5/demo1.tsx
(1 hunks)src/packages/cascader/demos/h5/demo2.tsx
(1 hunks)src/packages/cascader/demos/h5/demo3.tsx
(1 hunks)src/packages/cascader/demos/h5/demo4.tsx
(1 hunks)src/packages/cascader/demos/h5/demo5.tsx
(1 hunks)src/packages/cascader/demos/h5/demo6.tsx
(3 hunks)src/packages/cascader/demos/h5/demo7.tsx
(1 hunks)src/packages/cascader/demos/taro/demo1.tsx
(1 hunks)src/packages/cascader/demos/taro/demo2.tsx
(1 hunks)src/packages/cascader/demos/taro/demo3.tsx
(1 hunks)src/packages/cascader/demos/taro/demo4.tsx
(1 hunks)src/packages/cascader/demos/taro/demo5.tsx
(1 hunks)src/packages/cascader/demos/taro/demo6.tsx
(3 hunks)src/packages/cascader/demos/taro/demo7.tsx
(1 hunks)src/packages/cascader/doc.en-US.md
(4 hunks)src/packages/cascader/doc.md
(4 hunks)src/packages/cascader/doc.taro.md
(4 hunks)src/packages/cascader/doc.zh-TW.md
(4 hunks)src/packages/cascader/types.ts
(2 hunks)src/packages/cascader/utils.ts
(1 hunks)src/utils/is-empty.ts
(1 hunks)
🧰 Additional context used
🪛 GitHub Actions: CI
src/packages/cascader/__tests__/cascader.spec.tsx
[error] 143-143: Snapshot Cascader > visible true 1
mismatched
🪛 LanguageTool
src/packages/cascader/doc.zh-TW.md
[uncategorized] ~45-~45: 您的意思是“"不"透”?
Context: ...## 動態加載 lazy
屬性表示開啟資料的自動加載,Cascader 內部透過 value
和 onLoad
實作了自動載入資料的邏輯。 `laz...
(BU)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (34)
src/packages/cascader/demos/h5/demo6.tsx (3)
1-7
: 导入声明看起来不错!导入了必要的 React hooks 和类型定义,结构清晰。
24-86
: 注意选项结构中的潜在用户体验问题
- 在不同省份中存在重复的城市名称(如"温州"),这可能会导致用户混淆。
- 部分选项被禁用(disabled)但缺少视觉提示,可能影响用户理解。
建议:
- 为重复的地名添加更多上下文信息
- 为禁用选项添加提示信息
96-122
: 渲染结构组织合理!组件结构清晰,主题配置得当,props 传递正确。
src/packages/cascader/demos/taro/demo2.tsx (2)
1-7
: 代码结构优化得当!状态变量的命名更加规范,类型注解的添加提高了代码的类型安全性。
79-106
: 渲染逻辑实现合理!组件属性与状态管理保持一致,接口实现完整。
src/packages/cascader/utils.ts (2)
1-2
: 导入类型定义保持整体可读性良好。
这些类型定义能提高可维护性,但请确保与其他文件的类型引用保持一致,避免重复或冲突。
24-60
: 基于父子关系构建层级时,应关注顶层 ID 未匹配的情况。
当前仅返回map[topId]
,若topId
在来源数据中不存在,结果将是undefined
。若业务方需要在此场景下返回空数组,请在返回结果前加一次非空判断或兜底处理。src/packages/cascader/demos/h5/demo1.tsx (2)
1-2
: 引入方式和依赖组件在示例中正常。
导入useState
、useEffect
并结合Cascader
、Cell
的使用无明显问题。
100-103
: 使用onPathChange
打印路径时可作为调试信息。
如生产环境注重性能与安全,可移除或限制日志输出,避免跟踪信息过多。src/packages/cascader/cascader.tsx (1)
32-43
:CascaderPopupProps
补充 Popup 属性的做法可提高可扩展性。
请确保与PopupProps
的字段保持同步更新,避免后续出现功能不一致的风险。src/packages/cascader/cascader.taro.tsx (5)
16-29
: 引入本地工具函数与合并 Props 的逻辑值得肯定。
使用normalizeListOptions
、normalizeOptions
、mergeProps
等方法,能提高代码可读性与可重用性。
32-54
: 新增的CascaderPopupProps
与CascaderSupportPopupProps
类型定义层次清晰。
通过Pick
与Omit
组合出弹窗相关的部分属性,结构更灵活,可读性更强。
94-118
: 初始化合并 Props 与基础状态管理逻辑清晰,可读性较好。
forwardRef
便于父级直接调用开放的CascaderActions
。- 使用自定义 Hook (
useRefState
) 与getRefValue
管理options
,思路明确。
120-140
: 基于usePropsValue
管理受控与非受控的混合状态,提升灵活度。
- 请确认注释掉的
onPathChange
调用是否为刻意保留,若不再使用可移除,避免他人误解。isEmpty
判断与normalizeListOptions
、normalizeOptions
配合,确保容错性。
144-169
: 使用useMemo
动态计算级联层级的逻辑值得肯定,但需留意end
的计算分支。
若仅依赖opt?.children
判断是否结束,部分情况下(如空数组、缺失字段)可能导致逻辑分支遗漏。建议完善数据校验,确保下游使用安全。src/packages/cascader/demos/taro/demo5.tsx (2)
14-27
: 建议优化初始化逻辑与 H5 版本相同,建议改进初始化逻辑:
- 提取延迟时间常量
- 添加加载状态
- 添加错误处理
29-31
: 改进 onChange 的类型安全性与 H5 版本保持一致,建议改进类型定义。
src/packages/cascader/demo.tsx (3)
2-2
: 导入路径优化和新增演示组件导入路径的修改和新增 Demo7 组件的集成都很合理。
Also applies to: 9-9
15-15
: 翻译键命名优化翻译键的重命名和新增都保持了良好的一致性,使代码更易维护。
Also applies to: 20-20, 29-29, 33-33, 38-38
47-48
: 新增非受控模式演示新增的非受控模式演示补充了组件的使用场景。
src/packages/cascader/demo.taro.tsx (1)
47-62
:❓ Verification inconclusive
请验证 HTML 元素在 Taro 环境中的兼容性
将 Taro 组件替换为 HTML 元素(div, h2)可能会影响跨平台兼容性。建议验证在各端的表现。
🏁 Script executed:
#!/bin/bash # 搜索项目中 Taro 组件的使用模式 rg -A 2 "ScrollView|View" --type tsxLength of output: 66
检查 Taro 环境下 HTML 元素兼容性
建议在非 WEB 平台(例如小程序)上验证 demo.taro.tsx 中直接使用 HTML 标签(div, h2)的效果,确认其兼容性。当前代码将 Taro 提供的组件替换为普通 HTML 元素,可能导致部分平台显示或功能异常。请参考 Taro 官方文档,确保在所有目标平台上均无问题。如有兼容性问题,建议将相关 HTML 标签替换为 Taro 组件(例如 View、Text 等)。
- 文件:src/packages/cascader/demo.taro.tsx(第47-62行)
- 检查点:各目标平台(如微信小程序、支付宝小程序等)的元素渲染与交互表现
src/packages/cascader/demos/h5/demo4.tsx (1)
5-7
: 状态管理优化状态变量的命名更加统一和语义化,使用
useState
和类型注解的方式也更加规范。src/packages/cascader/demos/taro/demo7.tsx (2)
8-11
: 移除生产环境的调试代码与 H5 版本存在相同的问题,建议移除或控制调试输出。
Also applies to: 102-104
15-77
: 抽取共享的选项数据与 H5 版本存在相同的问题,建议将选项数据抽取到共享配置中。
src/packages/cascader/__tests__/cascader.spec.tsx (1)
215-221
: 异步测试实现优化异步加载测试的实现已优化,使用 Promise 和 setTimeout 提供了更清晰的异步行为。
src/packages/cascader/doc.md (2)
23-31
: 文档结构清晰完整新增的非受控用法部分,有助于用户更好地理解组件的不同使用方式。
54-58
: 文档说明准确且实用关于部分数据动态加载的说明非常清晰,特别是强调了无需设置
lazy
属性这一点,可以避免用户混淆。src/packages/cascader/doc.taro.md (4)
23-27
: 新增非受控示例说明
该部分为文档新增了“基础用法-非受控”示例,展示在非受控模式下如何通过传入options
列表使用 Cascader。示例结构清晰、易于理解。
45-46
: 更新动态加载说明
文档中更新了lazy
属性的描述,明确指出该属性必须与onLoad
同时设置,并且声明了onLoad
方法的返回类型为CascaderOption[]
。这有助于开发者正确使用自动加载逻辑。
56-57
: 新增部分数据动态加载说明
此处新增说明针对已设置初始options
的场景,详细描述了如何通过onLoad
方法实现部分数据的动态加载,并特别注明无需设置lazy
属性,内容表达清晰。
105-107
: 更新事件回调签名说明
Props 表中对onLoad
、onChange
以及onPathChange
的签名进行了更新,确保文档描述与组件实现保持一致,同时增强了类型安全性。src/packages/cascader/doc.en-US.md (3)
45-46
: 更新动态加载说明
文档中对lazy
属性与onLoad
回调的描述进行了更新,明确说明二者需要同时设置,并指出了onLoad
方法返回数据类型为CascaderOption[]
。该说明有助于用户正确理解自动加载的逻辑。
56-57
: 更新部分数据动态加载说明
这一部分详细解释了在设置初始options
后如何通过onLoad
方法加载数据,并明确告知用户在此场景下无需设置lazy
属性,描述清晰明了。
105-107
: 更新事件回调签名说明
Props 表中对onLoad
、onChange
与onPathChange
的签名已更新,确保文档和组件实现之间的一致性,增强了类型安全性,文档说明完整。
state.lazyLoadMap.delete(node) | ||
} | ||
|
||
const close = () => { | ||
setInnerVisible(false) | ||
onClose && onClose() | ||
} | ||
|
||
const closePopup = () => { | ||
close() | ||
} | ||
|
||
/* type: 是否是静默模式,是的话不触发事件 | ||
tabsCursor: tab的索引 */ | ||
const chooseItem = async (node: CascaderOption, type: boolean) => { | ||
if ((!type && node.disabled) || !state.panes[state.tabsCursor]) { | ||
return | ||
} | ||
// 如果没有子节点 | ||
if (state.tree.isLeaf(node, isLazy())) { | ||
node.leaf = true | ||
state.panes[state.tabsCursor].selectedNode = node | ||
state.panes = state.panes.slice(0, (node.level as number) + 1) | ||
if (!type) { | ||
const pathNodes = state.panes.map((item) => item.selectedNode) | ||
const optionParams = pathNodes.map((item: any) => item.value) | ||
onChange(optionParams, pathNodes) | ||
onPathChange?.(optionParams, pathNodes) | ||
setInnerValue(optionParams) | ||
// 如果需要处理最终结果,可以在这里使用 last | ||
setInnerOptions(parent.children) | ||
} catch (error) { | ||
console.error('Error loading data:', error) | ||
} | ||
setOptionsData(state.panes) | ||
close() | ||
return | ||
} | ||
// 如果有子节点,滑到下一个 | ||
if (state.tree.hasChildren(node, isLazy())) { | ||
const level = (node.level as number) + 1 | ||
|
||
state.panes[state.tabsCursor].selectedNode = node | ||
state.panes = state.panes.slice(0, level) | ||
state.tabsCursor = level | ||
state.panes.push({ | ||
nodes: node.children || [], | ||
selectedNode: null, | ||
paneKey: `c${state.tabsCursor + 1}`, | ||
}) | ||
setOptionsData(state.panes) | ||
setTabvalue(`c${state.tabsCursor + 1}`) | ||
|
||
if (!type) { | ||
const pathNodes = state.panes.map((item) => item.selectedNode) | ||
const optionParams = pathNodes.map((item: any) => item?.value) | ||
onPathChange?.(optionParams, pathNodes) | ||
if (lazy) load() | ||
}, [lazy]) | ||
|
||
const chooseItem = async (pane: CascaderOption, levelIndex: number) => { | ||
if (pane.disabled) return | ||
const nextValue = innerValue.slice(0, levelIndex) | ||
const nextPathNodes = pathNodes.current.slice(0, levelIndex) | ||
if (pane.value) { | ||
setLoading(!!onLoad && { [levelIndex]: pane.value }) | ||
nextValue[levelIndex] = pane.value | ||
nextPathNodes[levelIndex] = pane | ||
pathNodes.current = nextPathNodes | ||
props?.onPathChange?.(nextValue, pathNodes.current) | ||
} | ||
if (onLoad) { | ||
// 叶子节点不操作 | ||
if (!pane.leaf) { | ||
const asyncOptions = await onLoad(pane, levelIndex) | ||
// 修改 options 触发渲染逻辑 | ||
if (asyncOptions) pane.children = asyncOptions | ||
} else { | ||
setVisible(false) | ||
setValue(nextValue) | ||
} | ||
return | ||
} | ||
state.currentProcessNode = node | ||
if (node.loading) { | ||
return | ||
if (!pane.children && !onLoad) { | ||
setVisible(false) | ||
setValue(nextValue) | ||
} | ||
|
||
await invokeLazyLoad(node) | ||
if (state.currentProcessNode === node) { | ||
state.panes[state.tabsCursor].selectedNode = node | ||
chooseItem(node, type) | ||
} | ||
setOptionsData(state.panes) | ||
setInnerValue(nextValue) | ||
setLoading({}) | ||
} |
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.
🛠️ Refactor suggestion
核心状态管理逻辑合理,但部分异步控制需进一步规范。
usePropsValue
与useRefState
配合可减少不必要的 re-render,但需明确每次数据更新路径,以免覆盖外部传入的 props。- 对
onLoad
处理的异步结果,如出现异常时,目前仅简单地打印日志,建议提供更明确的错误回调或 UI 提示信息。 - 当懒加载时,如后续层级数据量较大,
onLoad
频繁调用可能带来性能开销,可考虑加缓存策略或分页处理。
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat_v3.x #3007 +/- ##
=============================================
+ Coverage 85.79% 85.85% +0.06%
=============================================
Files 281 282 +1
Lines 18527 18281 -246
Branches 2810 2766 -44
=============================================
- Hits 15896 15696 -200
+ Misses 2626 2580 -46
Partials 5 5 ☔ View full report in Codecov by Sentry. |
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
🧹 Nitpick comments (4)
src/packages/address/customRender.tsx (1)
14-15
: 建议为value
属性提供默认值接口中将
value
和defaultValue
设置为必需属性是一个好的改进,但建议在defaultProps
中也为value
提供默认值,以确保组件在未传入该属性时的行为一致性。const defaultProps = { ...ComponentDefaults, + value: [], visible: false, type: 'custom', options: [],
src/packages/address/customRender.taro.tsx (1)
14-15
: 建议为value
属性提供默认值接口中将
value
和defaultValue
设置为必需属性是一个好的改进,但建议在defaultProps
中也为value
提供默认值,以确保组件在未传入该属性时的行为一致性。const defaultProps = { ...ComponentDefaults, + value: [], visible: false, type: 'custom', options: [],
src/packages/address/address.tsx (1)
30-31
: 建议为value
属性提供默认值接口中将
value
和defaultValue
设置为必需属性是一个好的改进,但建议在defaultProps
中也为value
提供默认值,以确保组件在未传入该属性时的行为一致性。const defaultProps = { ...ComponentDefaults, + value: [], defaultValue: [], type: 'custom', options: [],
src/packages/address/address.taro.tsx (1)
31-32
: 建议为value
属性提供默认值接口中将
value
和defaultValue
设置为必需属性是一个好的改进,但建议在defaultProps
中也为value
提供默认值,以确保组件在未传入该属性时的行为一致性。const defaultProps = { ...ComponentDefaults, + value: [], defaultValue: [], type: 'custom', options: [],
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
src/packages/address/__test__/__snapshots__/address.spec.tsx.snap
is excluded by!**/*.snap
src/packages/cascader/__tests__/__snapshots__/cascader.spec.tsx.snap
is excluded by!**/*.snap
📒 Files selected for processing (4)
src/packages/address/address.taro.tsx
(1 hunks)src/packages/address/address.tsx
(1 hunks)src/packages/address/customRender.taro.tsx
(1 hunks)src/packages/address/customRender.tsx
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (2)
src/packages/address/address.tsx (1)
154-170
: 验证 CustomRender 组件的 value 属性传递注意到
CustomRender
组件没有传递value
属性,这可能会导致类型错误或未定义的行为。建议检查并确保正确传递该属性。<CustomRender visible={innerVisible} closeable title={title || locale.address.selectRegion} left={renderLeftOnCustomSwitch()} + value={value} defaultValue={defaultValue} closeIcon={closeIcon} options={options}
src/packages/address/address.taro.tsx (1)
156-172
: 验证 CustomRender 组件的 value 属性传递注意到
CustomRender
组件没有传递value
属性,这可能会导致类型错误或未定义的行为。建议检查并确保正确传递该属性。<CustomRender visible={innerVisible} closeable title={title || locale.address.selectRegion} left={renderLeftOnCustomSwitch()} + value={value} defaultValue={defaultValue} closeIcon={closeIcon} options={options}
Summary by CodeRabbit
新功能
增强功能
Cascader
组件的属性,强制要求value
和defaultValue
为必填项。文档更新