-
Notifications
You must be signed in to change notification settings - Fork 267
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 #2956
base: next
Are you sure you want to change the base?
refactor: cascader #2956
Conversation
概述遍历这个拉取请求对Cascader组件进行了全面的重构和改进。主要变更包括重新设计组件的状态管理、简化测试套件、更新文档,以及引入新的实用函数来处理级联选择器的选项。这些修改旨在提高组件的灵活性、性能和可维护性。 变更
建议的审阅者
相关的拉取请求
诗歌
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: 16
🧹 Nitpick comments (29)
src/packages/cascader/demos/h5/demo5.tsx (3)
1-7
: 代码结构清晰,但可以改进类型定义!状态管理的重构很好,变量命名更加简洁。建议为了更好的类型安全性,可以定义一个类型来描述选择器的值类型。
type CascaderValue = string[]; const [value, setValue] = useState<CascaderValue>([]);
29-30
: 建议添加具体的类型定义onChange 处理函数使用了 any 类型,这降低了代码的类型安全性。建议:
const onChange = (value: string[], path: CascaderOption[]) => { setValue(value); };
32-54
: 建议增加无障碍访问支持组件的基本功能实现良好,但建议增加以下无障碍访问支持:
- 为 Cell 添加 aria-label 属性
- 为 Cascader 添加 aria-expanded 状态
- 添加键盘导航支持
<Cell title="选择地址" description={value.length ? value : '请选择地址'} + aria-label="地址选择器" + role="button" onClick={() => { setVisible(true) }} />src/packages/cascader/demos/h5/demo6.tsx (4)
22-89
: 建议优化数据加载策略
使用 setTimeout 延迟 300ms 加载数据可能会影响用户体验。建议考虑以下优化方案:
- 使用加载状态指示器
- 考虑使用骨架屏(Skeleton)
- 如果可能,减少延迟时间
代码中存在被注释的代码(第24行),建议清理无用代码。
建议应用以下改进:
useEffect(() => { + const loadOptions = async () => { + setLoading(true) try { - setTimeout(() => { - // setValue(['浙江', '温州', '鹿城区']) setOptions([/* ... */]) - }, 300) + } finally { + setLoading(false) + } + } + loadOptions() }, [])
27-87
: 建议改进数据结构设计
数据中存在重复的地区名称,例如不同省份下都有"西湖区"和"温州",这可能会导致混淆。建议:
- 为每个选项添加唯一标识符
- 考虑使用更具区分性的命名
disabled 状态的使用需要注意:
- 当父节点被禁用时,其子节点的状态可能造成困惑
- 建议在文档中说明禁用状态的继承规则
建议的数据结构改进:
{ value: '浙江', text: '浙江', + id: 'ZJ', children: [ { value: '杭州', text: '杭州', + id: 'ZJ-HZ', disabled: true, children: [ { value: '西湖区', text: '西湖区', + id: 'ZJ-HZ-XH', disabled: true } ] } ] }
90-94
: 建议加强类型安全性事件处理函数使用了
any
类型,建议使用具体的类型定义:- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) } - const onPathChange = (value: any, path: any) => { + const onPathChange = (value: string[], path: CascaderOption[]) => { console.log('onPathChange', value, path) }
Line range hint
96-123
: 建议增强可访问性组件的渲染结构清晰,但建议添加以下可访问性改进:
- 为可交互元素添加
aria-label
属性- 确保颜色对比度符合 WCAG 标准
- 添加键盘导航支持
<Cell title="选择地址" description={value.length ? value : '请选择地址'} + aria-label="选择地址按钮" + role="button" onClick={() => { setVisible(true) }} /> <ConfigProvider theme={customTheme}> <Cascader visible={visible} activeColor="#3768FA" value={value} title="选择地址" options={options} closeable activeIcon="star" + aria-label="地址选择器" + role="dialog" onClose={() => { setVisible(false) }} onChange={onChange} onPathChange={onPathChange} /> </ConfigProvider>src/packages/cascader/demos/taro/demo1.tsx (2)
6-10
: 类型安全性改进建议建议添加更严格的类型定义以提高代码的可维护性和类型安全性。
- const [value, setValue] = useState([]) + const [value, setValue] = useState<string[]>([]) - const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) }
81-86
: 提升无障碍访问性建议添加适当的 ARIA 属性以提升组件的无障碍访问性。
<Cell title="选择地址" description={value.length ? value : '请选择地址'} + role="button" + aria-haspopup="listbox" + aria-expanded={visible} onClick={() => { setVisible(true) }} />src/packages/cascader/demos/taro/demo6.tsx (1)
Line range hint
9-16
: 优化主题配置管理建议将主题配置提取到独立的配置文件中,以便复用和统一管理。
+// src/packages/cascader/demos/taro/theme-configs.ts +export const blueTheme = { + nutuiCascaderItemHeight: '48px', + nutuiCascaderItemMargin: '0 10px', + // ... +} -const customTheme = { - nutuiCascaderItemHeight: '48px', - nutuiCascaderItemMargin: '0 10px', - // ... -} +import { blueTheme } from './theme-configs'src/packages/cascader/demos/h5/demo3.tsx (2)
25-26
: 建议完善类型定义
onChange
函数的参数使用any
类型过于宽松,建议使用更具体的类型定义。- const onChange = (value: any, path: any) => { + const onChange = (value: CascaderValue, path: CascaderOption[]) => {
8-24
: 优化异步加载实现
loadCascaderItemData
的实现逻辑清晰,但建议考虑以下改进:
- 添加错误处理
- 使用更合理的超时时间
const loadCascaderItemData = ( node: CascaderOption, level: number ): Promise<CascaderOption[]> => { return new Promise((resolve) => { + return new Promise((resolve, reject) => { setTimeout(() => { + try { const { value } = node const text = value?.toString().substring(0, 1) const value1 = `${text}${level + 1}1` const value2 = `${text}${level + 1}2` resolve([ { value: value1, text: value1, leaf: level >= 2 }, { value: value2, text: value2, leaf: level >= 2 }, ]) + } catch (error) { + reject(error) + } }, 500) }) }src/packages/cascader/demos/taro/demo5.tsx (2)
14-27
: 建议优化初始化逻辑在演示组件中使用
setTimeout
进行状态初始化显得多余,建议直接在useEffect
中设置状态。这样可以减少不必要的延迟,提高用户体验。useEffect(() => { - setTimeout(() => { setValue(['广东省', '广州市']) setOptions([ { value: '北京', text: '北京', id: 1, pidd: null }, { value: '通州区', text: '通州区', id: 11, pidd: 1, sortKey: 2 }, { value: '大兴区', text: '大兴区', id: 12, pidd: 1, sortKey: 1 }, { value: '经海路', text: '经海路', id: 111, pidd: 12, sortKey: 2 }, { value: '黄亦路', text: '黄亦路', id: 112, pidd: 12, sortKey: 1 }, { value: '广东省', text: '广东省', id: 2, pidd: null }, { value: '广州市', text: '广州市', id: 21, pidd: 2 }, ]) - }, 300) }, [])
8-12
: 建议统一命名规范
format
对象中使用的pidd
键名与标准的pid
不一致,建议统一使用pid
作为父级 ID 的键名。const format = { topId: null, idKey: 'id', - pidKey: 'pidd', + pidKey: 'pid', }src/packages/cascader/utils.ts (1)
40-48
: 建议优化类型定义当前代码中使用了
any
类型,建议使用更具体的类型定义来提高代码的类型安全性。- const newNode: any = { pid, id, ...others } + interface TreeNode extends CascaderOption { + pid: string | null + id: string | number + } + const newNode: TreeNode = { pid, id, ...others }src/packages/cascader/demos/h5/demo4.tsx (2)
25-41
: 建议优化异步加载示例当前的
lazyLoadDemo4
实现使用了setTimeout
来模拟异步加载,建议添加注释说明这只是演示用途,并展示更贴近实际场景的示例代码。+ // 注意:此处使用 setTimeout 仅用于演示。实际应用中应该使用真实的 API 调用。 const lazyLoadDemo4 = async ( - node: any, + node: CascaderOption, level: number ): Promise<CascaderOption[]> => { return new Promise((resolve) => { setTimeout(() => { const { value } = node const text = value.substring(0, 1) const value1 = `${text}${level + 1}1` const value2 = `${text}${level + 1}2` resolve([ { value: value1, text: value1, leaf: level >= 2 }, { value: value2, text: value2, leaf: level >= 1 }, ]) }, 500) }) }
42-43
: 建议完善类型定义
change4
函数的参数使用了any
类型,建议明确定义参数类型以提高代码的可维护性。- const change4 = (value: any, path: any) => { + const change4 = (value: string[], path: CascaderOption[]) => {src/packages/cascader/demos/taro/demo4.tsx (1)
29-40
: 建议优化性能处理使用固定的延迟时间(500ms)可能会影响用户体验。建议:
- 考虑使用动态超时时间
- 添加加载状态指示器
src/packages/cascader/demos/h5/demo7.tsx (1)
12-79
: 建议优化数据加载机制使用固定的 300ms 延迟加载初始数据可能不是最佳实践:
- 可能导致不必要的等待
- 在网络条件较差时可能不够用
建议:
- 考虑使用动态加载机制
- 添加加载状态提示
src/packages/cascader/demos/taro/demo7.tsx (3)
8-11
: 建议改进类型安全性
onChange
处理函数中的参数类型使用any
过于宽松,建议使用更具体的类型定义。- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { console.log('onchange', value, path) setValue(value) }
12-79
: 建议优化初始化逻辑使用
setTimeout
模拟异步加载数据可能会影响测试和用户体验。建议:
- 考虑使用 loading 状态来处理异步加载
- 在实际场景中使用真实的 API 调用
82-88
: 建议增加无障碍支持为了提高组件的可访问性,建议添加 ARIA 属性:
<Cell title="选择地址" description={value.length ? value : '请选择地址'} + role="button" + aria-haspopup="listbox" + aria-expanded={visible} onClick={() => { setVisible(true) }} />src/packages/cascader/__tests__/cascader.spec.tsx (1)
214-228
: 建议增强延迟加载测试当前的测试实现可以进一步改进:
- 添加对错误情况的测试
- 验证加载状态的变化
- 测试不同的数据结构
it('select with lazy', async () => { const lazyFunc = vi.fn() + const mockError = new Error('Loading failed') const { container } = render( <Cascader lazy value={['test']} onLoad={async (node: any) => { + if (node.value === 'error') { + throw mockError + } return new Promise((resolve) => { setTimeout(() => { lazyFunc() resolve([] as CascaderOption[]) }, 50) }) }} /> ) expect(lazyFunc).not.toBeCalled() await waitFor(() => { expect(lazyFunc).toBeCalled() }) + // Test error handling + await expect(async () => { + fireEvent.click(container.querySelector('.error-node')) + }).rejects.toThrow(mockError) })src/packages/cascader/doc.md (2)
23-31
: 建议完善文档示例新增的非受控用法部分建议添加:
- 更详细的代码示例
- 常见用例说明
- 与受控用法的对比说明
105-107
: API 文档更新建议API 文档的更新需要补充:
- 参数的详细类型定义
- 返回值的具体说明
- 各种场景下的使用示例
src/packages/cascader/doc.zh-TW.md (2)
57-57
: 修复 Markdown 格式强调标记内不应该有空格。
-**無需設定 `lazy` 屬性。 ** +**無需設定 `lazy` 屬性。**🧰 Tools
🪛 Markdownlint (0.37.0)
57-57: null
Spaces inside emphasis markers(MD037, no-space-in-emphasis)
105-107
: 建议改进类型定义回调函数的参数类型使用
any
过于宽松,建议使用更具体的类型定义:
node
应该使用CascaderOption
类型pathNodes
应该使用CascaderOption[]
类型-| onLoad | 動態加載回調,開啟動態加載時生效 | `(node: any) => void` | `-` | -| onChange | 選中值改變時觸發 | `(value: CascaderValue, pathNodes?: any) => void` | `-` | -| onPathChange | 選中項改變時觸發 | `(value: CascaderValue, pathNodes: any) => void` | `-` | +| onLoad | 動態加載回調,開啟動態加載時生效 | `(node: CascaderOption) => void` | `-` | +| onChange | 選中值改變時觸發 | `(value: CascaderValue, pathNodes?: CascaderOption[]) => void` | `-` | +| onPathChange | 選中項改變時觸發 | `(value: CascaderValue, pathNodes: CascaderOption[]) => void` | `-` |src/packages/cascader/doc.en-US.md (2)
57-57
: 修复 Markdown 格式强调标记内不应该有空格。
-**No need to set the `lazy` attribute. ** +**No need to set the `lazy` attribute.**🧰 Tools
🪛 Markdownlint (0.37.0)
57-57: null
Spaces inside emphasis markers(MD037, no-space-in-emphasis)
105-107
: 建议改进类型定义回调函数的参数类型使用
any
过于宽松,建议使用更具体的类型定义:
node
应该使用CascaderOption
类型pathNodes
应该使用CascaderOption[]
类型-| onLoad | Dynamic loading callback, which takes effect when dynamic loading is enabled | `(node: any) => void` | `-` | -| onChange | Triggered when the selected value changes | `(value: CascaderValue, pathNodes?: any) => void` | `-` | -| onPathChange | Triggered when the selected item changes | `(value: CascaderValue, pathNodes: any) => void` | `-` | +| onLoad | Dynamic loading callback, which takes effect when dynamic loading is enabled | `(node: CascaderOption) => void` | `-` | +| onChange | Triggered when the selected value changes | `(value: CascaderValue, pathNodes?: CascaderOption[]) => void` | `-` | +| onPathChange | Triggered when the selected item changes | `(value: CascaderValue, pathNodes: CascaderOption[]) => void` | `-` |
📜 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 (29)
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
(4 hunks)src/packages/cascader/demo.tsx
(4 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/helper.ts
(0 hunks)src/packages/cascader/tree.ts
(0 hunks)src/packages/cascader/types.ts
(2 hunks)src/packages/cascader/utils.ts
(1 hunks)src/packages/tabs/tabs.tsx
(1 hunks)src/utils/is-empty.ts
(1 hunks)
💤 Files with no reviewable changes (2)
- src/packages/cascader/tree.ts
- src/packages/cascader/helper.ts
🧰 Additional context used
🪛 Markdownlint (0.37.0)
src/packages/cascader/doc.en-US.md
57-57: null
Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
src/packages/cascader/doc.zh-TW.md
57-57: null
Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
🪛 LanguageTool
src/packages/cascader/doc.zh-TW.md
[uncategorized] ~45-~45: 您的意思是“"不"透”?
Context: ...## 動態加載 lazy
屬性表示開啟資料的自動加載,Cascader 內部透過 value
和 onLoad
實作了自動載入資料的邏輯。 `laz...
(BU)
🔇 Additional comments (11)
src/packages/cascader/demos/h5/demo5.tsx (1)
8-12
: 请确认排序功能是否受影响format 对象中移除了 sortKey,但 options 中的一些选项仍然保留了 sortKey 属性。需要确认:
- 排序功能是否仍然正常工作
- sortKey 属性是否仍然需要保留在选项中
src/packages/cascader/demos/h5/demo6.tsx (1)
1-7
: 代码结构优化得当!状态变量的命名更加清晰,并且添加了类型定义,提高了代码的可维护性和类型安全性。
Also applies to: 19-21
src/packages/cascader/demos/taro/demo2.tsx (1)
89-102
: 检查默认值与数据结构的匹配性当前的
defaultValue
使用的是标准键名(['福建', '福州', '台江区']
),但数据结构使用的是自定义键名(value1
)。这可能导致选择器无法正确匹配默认值。建议确保默认值与数据结构匹配:
- defaultValue={value} + defaultValue={['福建', '福州', '台江区'].map(v => ({ value1: v }))}或者更好的方案是统一使用标准键名,移除 optionKey 配置:
- optionKey={{ - textKey: 'text1', - valueKey: 'value1', - childrenKey: 'items', - }}src/utils/is-empty.ts (1)
1-6
: 函数实现正确,逻辑清晰
isEmpty
函数逻辑正确,能够有效判断传入的参数是否为空。src/packages/cascader/types.ts (2)
15-16
: 注意索引签名可能带来的类型安全问题添加
[key: string]: any
索引签名虽然提供了更大的灵活性,但也可能导致类型检查失效,建议仅在确实需要动态属性时使用。建议考虑以下替代方案:
- 使用 Pick/Omit 等工具类型来限制允许的属性
- 显式声明所有可能的属性,以保持类型安全
40-43
: LGTM - 新增的 CascaderActions 类型定义清晰明确类型定义简洁且符合组件的开放/关闭行为需求。
src/packages/cascader/demo.tsx (1)
9-9
: LGTM - 新增非受控组件示例新增的 Demo7 组件和相关翻译完善了组件的示例文档。
Also applies to: 47-48
src/packages/cascader/demo.taro.tsx (1)
11-11
: 代码变更合理新增的非受控组件示例及其相关翻译内容组织合理,符合组件文档规范。
Also applies to: 17-17, 26-26, 35-35, 50-51
src/packages/cascader/demos/taro/demo4.tsx (1)
4-4
: 需要添加单元测试当前缺少单元测试覆盖,这可能会导致潜在的问题在生产环境中才被发现。
需要我帮您生成单元测试代码吗?
src/packages/cascader/__tests__/cascader.spec.tsx (1)
Line range hint
169-185
: 测试用例更新正确选择器的更新正确反映了组件结构的变化,确保了测试的准确性。
src/packages/tabs/tabs.tsx (1)
27-27
: 建议重新考虑类型定义的改变将
title
属性的返回类型从JSX.Element[]
改为Element[]
可能会降低类型安全性。建议:
- 保持使用
JSX.Element[]
以获得更好的类型检查- 如果需要更灵活的类型,考虑使用
ReactNode[]
useEffect(() => { | ||
setTimeout(() => { | ||
setValue(['广东省', '广州市']) | ||
setOptions([ | ||
{ value: '北京', text: '北京', id: 1, pidd: null }, | ||
{ value: '通州区', text: '通州区', id: 11, pidd: 1, sortKey: 2 }, | ||
{ value: '大兴区', text: '大兴区', id: 12, pidd: 1, sortKey: 1 }, | ||
{ value: '经海路', text: '经海路', id: 111, pidd: 12, sortKey: 2 }, | ||
{ value: '黄亦路', text: '黄亦路', id: 112, pidd: 12, sortKey: 1 }, | ||
{ value: '广东省', text: '广东省', id: 2, pidd: null }, | ||
{ value: '广州市', text: '广州市', id: 21, pidd: 2 }, | ||
]) | ||
}, 300) | ||
}, []) |
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
建议改进异步数据加载的实现
当前使用 setTimeout 模拟异步加载数据的方式不适合生产环境。建议:
- 使用实际的异步数据获取方法
- 添加加载状态指示器
- 处理可能的错误情况
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetchOptions();
setOptions(response);
setValue(['广东省', '广州市']);
} catch (error) {
console.error('Failed to fetch options:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
children: [ | ||
{ value: '鹿城区', text: '鹿城区' }, | ||
{ value: '瓯海区', text: '瓯海区' }, | ||
{ | ||
value: '杭州', | ||
text: '杭州', | ||
disabled: true, | ||
children: [ | ||
{ value: '西湖区', text: '西湖区', disabled: true }, | ||
{ value: '余杭区', text: '余杭区' }, | ||
], | ||
}, | ||
{ | ||
value: '温州', | ||
text: '温州', | ||
children: [ | ||
{ value: '鹿城区', text: '鹿城区' }, | ||
{ value: '瓯海区', text: '瓯海区' }, | ||
], | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
value: '湖南', | ||
text: '湖南', | ||
disabled: true, | ||
children: [ | ||
{ | ||
value: '长沙', | ||
text: '长沙', | ||
value: '湖南', | ||
text: '湖南', | ||
disabled: true, | ||
children: [ | ||
{ value: '芙蓉区', text: '芙蓉区' }, | ||
{ value: '岳麓区', text: '岳麓区' }, | ||
{ | ||
value: '长沙', | ||
text: '长沙', | ||
disabled: true, | ||
children: [ | ||
{ value: '芙蓉区', text: '芙蓉区' }, | ||
{ value: '岳麓区', text: '岳麓区' }, | ||
], | ||
}, | ||
{ | ||
value: '岳阳', | ||
text: '岳阳', | ||
children: [ | ||
{ value: '岳阳楼区', text: '岳阳楼区' }, | ||
{ value: '云溪区', text: '云溪区' }, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
value: '岳阳', | ||
text: '岳阳', | ||
value: '福建', | ||
text: '福建', | ||
children: [ | ||
{ value: '岳阳楼区', text: '岳阳楼区' }, | ||
{ value: '云溪区', text: '云溪区' }, | ||
{ | ||
value: '福州', | ||
text: '福州', | ||
children: [ | ||
{ value: '鼓楼区', text: '鼓楼区' }, | ||
{ value: '台江区', text: '台江区' }, | ||
], | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
value: '福建', | ||
text: '福建', | ||
children: [ | ||
{ | ||
value: '福州', | ||
text: '福州', | ||
children: [ | ||
{ value: '鼓楼区', text: '鼓楼区' }, | ||
{ value: '台江区', text: '台江区' }, | ||
], | ||
}, | ||
], | ||
}, | ||
]) | ||
const change1 = (value: any, path: any) => { | ||
console.log('onChange', value, path) | ||
setValue1(value) | ||
} | ||
|
||
]) | ||
}, 300) | ||
}, []) |
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
建议优化数据加载逻辑
- setTimeout 模拟异步加载不是最佳实践,建议改用实际的数据获取方法。
- 缺少加载状态指示器,可能影响用户体验。
建议如下改进:
+ const [loading, setLoading] = useState(true)
useEffect(() => {
- setTimeout(() => {
+ const fetchOptions = async () => {
+ setLoading(true)
+ try {
setOptions([/* ... */])
+ } finally {
+ setLoading(false)
+ }
+ }
+ fetchOptions()
- }, 300)
}, [])
📝 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.
useEffect(() => { | |
setTimeout(() => { | |
setOptions([ | |
{ | |
value: '温州', | |
text: '温州', | |
value: '浙江', | |
text: '浙江', | |
children: [ | |
{ value: '鹿城区', text: '鹿城区' }, | |
{ value: '瓯海区', text: '瓯海区' }, | |
{ | |
value: '杭州', | |
text: '杭州', | |
disabled: true, | |
children: [ | |
{ value: '西湖区', text: '西湖区', disabled: true }, | |
{ value: '余杭区', text: '余杭区' }, | |
], | |
}, | |
{ | |
value: '温州', | |
text: '温州', | |
children: [ | |
{ value: '鹿城区', text: '鹿城区' }, | |
{ value: '瓯海区', text: '瓯海区' }, | |
], | |
}, | |
], | |
}, | |
], | |
}, | |
{ | |
value: '湖南', | |
text: '湖南', | |
disabled: true, | |
children: [ | |
{ | |
value: '长沙', | |
text: '长沙', | |
value: '湖南', | |
text: '湖南', | |
disabled: true, | |
children: [ | |
{ value: '芙蓉区', text: '芙蓉区' }, | |
{ value: '岳麓区', text: '岳麓区' }, | |
{ | |
value: '长沙', | |
text: '长沙', | |
disabled: true, | |
children: [ | |
{ value: '芙蓉区', text: '芙蓉区' }, | |
{ value: '岳麓区', text: '岳麓区' }, | |
], | |
}, | |
{ | |
value: '岳阳', | |
text: '岳阳', | |
children: [ | |
{ value: '岳阳楼区', text: '岳阳楼区' }, | |
{ value: '云溪区', text: '云溪区' }, | |
], | |
}, | |
], | |
}, | |
{ | |
value: '岳阳', | |
text: '岳阳', | |
value: '福建', | |
text: '福建', | |
children: [ | |
{ value: '岳阳楼区', text: '岳阳楼区' }, | |
{ value: '云溪区', text: '云溪区' }, | |
{ | |
value: '福州', | |
text: '福州', | |
children: [ | |
{ value: '鼓楼区', text: '鼓楼区' }, | |
{ value: '台江区', text: '台江区' }, | |
], | |
}, | |
], | |
}, | |
], | |
}, | |
{ | |
value: '福建', | |
text: '福建', | |
children: [ | |
{ | |
value: '福州', | |
text: '福州', | |
children: [ | |
{ value: '鼓楼区', text: '鼓楼区' }, | |
{ value: '台江区', text: '台江区' }, | |
], | |
}, | |
], | |
}, | |
]) | |
const change1 = (value: any, path: any) => { | |
console.log('onChange', value, path) | |
setValue1(value) | |
} | |
]) | |
}, 300) | |
}, []) | |
const [loading, setLoading] = useState(true) | |
useEffect(() => { | |
const fetchOptions = async () => { | |
setLoading(true) | |
try { | |
setOptions([ | |
{ | |
value: '浙江', | |
text: '浙江', | |
children: [ | |
{ | |
value: '杭州', | |
text: '杭州', | |
disabled: true, | |
children: [ | |
{ value: '西湖区', text: '西湖区', disabled: true }, | |
{ value: '余杭区', text: '余杭区' }, | |
], | |
}, | |
{ | |
value: '温州', | |
text: '温州', | |
children: [ | |
{ value: '鹿城区', text: '鹿城区' }, | |
{ value: '瓯海区', text: '瓯海区' }, | |
], | |
}, | |
], | |
}, | |
{ | |
value: '湖南', | |
text: '湖南', | |
disabled: true, | |
children: [ | |
{ | |
value: '长沙', | |
text: '长沙', | |
disabled: true, | |
children: [ | |
{ value: '芙蓉区', text: '芙蓉区' }, | |
{ value: '岳麓区', text: '岳麓区' }, | |
], | |
}, | |
{ | |
value: '岳阳', | |
text: '岳阳', | |
children: [ | |
{ value: '岳阳楼区', text: '岳阳楼区' }, | |
{ value: '云溪区', text: '云溪区' }, | |
], | |
}, | |
], | |
}, | |
{ | |
value: '福建', | |
text: '福建', | |
children: [ | |
{ | |
value: '福州', | |
text: '福州', | |
children: [ | |
{ value: '鼓楼区', text: '鼓楼区' }, | |
{ value: '台江区', text: '台江区' }, | |
], | |
}, | |
], | |
}, | |
]) | |
} finally { | |
setLoading(false) | |
} | |
} | |
fetchOptions() | |
}, []) |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## next #2956 +/- ##
==========================================
+ Coverage 84.20% 84.22% +0.01%
==========================================
Files 267 267
Lines 18125 17910 -215
Branches 2671 2633 -38
==========================================
- Hits 15263 15084 -179
+ Misses 2857 2821 -36
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 (3)
src/packages/address/address.tsx (1)
30-31
: 实现方式值得肯定使用
usePropsValue
来管理状态是个很好的做法,它能够正确处理受控和非受控的情况。建议在文档中说明这两个属性的使用方式。// 建议在属性注释中添加使用说明 export interface AddressProps extends CascaderProps { + /** 当前选中的值(受控) */ value: CascaderValue + /** 默认选中的值(非受控) */ defaultValue: CascaderValuesrc/packages/address/address.taro.tsx (2)
30-31
: 建议完善类型定义和文档代码实现保持了良好的一致性,但建议:
- 为了更好的开发体验,建议给
CascaderValue
类型添加更详细的文档说明- 考虑添加类型测试以确保类型定义的正确性
让我们检查一下
CascaderValue
的使用情况:#!/bin/bash # 搜索 CascaderValue 的定义和使用 ast-grep --pattern 'type CascaderValue = $$$'
30-31
: 关于此次改动的整体建议
接口变更
- 将
value
和defaultValue
改为必选是一个破坏性更改- 建议在下一个主版本更新中进行此变更
- 需要在更新文档中明确说明此变更
文档完善
- 补充类型定义的详细说明
- 添加受控和非受控使用的示例代码
- 更新升级指南
测试建议
- 添加类型测试
- 补充边界情况的单元测试
- 添加 E2E 测试确保功能正常
Also applies to: 14-15
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/packages/address/__test__/__snapshots__/address.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: build
🔇 Additional comments (2)
src/packages/address/customRender.tsx (1)
14-15
:⚠️ Potential issue需要注意接口变更可能导致的兼容性问题
将
value
和defaultValue
从可选改为必选是一个破坏性更改。虽然有 defaultProps 提供默认值,但这种改动可能会影响现有代码。建议:
- 在升级指南中说明这个变更
- 考虑是否真的需要将这些属性设为必选
让我们验证一下这个改动的影响范围:
src/packages/address/customRender.taro.tsx (1)
14-15
: 保持了 Web 和 Taro 版本的一致性接口变更与 Web 版本保持一致,这有助于代码维护。但同样需要注意兼容性问题。
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
♻️ Duplicate comments (1)
src/packages/cascader/demos/taro/demo6.tsx (1)
89-93
: 🛠️ Refactor suggestion建议完善事件处理器实现
- 需要添加正确的类型注解
onPathChange
应该实现实际功能或移除- const onChange = (value: any, path: any) => { + const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) } - const onPathChange = (value: any, path: any) => { - console.log('onPathChange', value, path) + const onPathChange = (value: string[], path: CascaderOption[]) => { + // 实现路径变更的实际处理逻辑 }
🧹 Nitpick comments (9)
src/packages/cascader/doc.taro.md (3)
45-46
: 建议增加代码示例说明返回值类型为了更好地帮助开发者理解,建议在
onLoad
方法的返回值类型说明中添加一个简单的代码示例。// 示例代码 const onLoad = async (node: CascaderOption): Promise<CascaderOption[]> => { return [ { text: '选项1', value: '1' }, { text: '选项2', value: '2' } ] }
56-58
: 说明清晰,建议补充示例场景部分数据动态加载的说明很清楚,特别是强调了无需设置
lazy
属性这一重要细节。建议补充一个具体的应用场景示例,以帮助开发者更好理解。
105-107
: 建议完善类型定义说明Props 表格中的类型定义可以更详细:
onLoad
的参数类型建议明确说明node
的具体结构CascaderValue
类型需要在文档中说明具体定义pathNodes
参数的具体数据结构建议添加示例说明建议添加如下类型说明:
interface CascaderOption { value: string | number text: string children?: CascaderOption[] // 其他可能的属性... } type CascaderValue = (string | number)[]src/packages/cascader/demos/h5/demo6.tsx (2)
22-88
: 建议优化模拟数据加载方式在演示组件中使用
setTimeout
模拟数据加载可能会影响用户体验,建议考虑以下方案:
- 直接初始化数据
- 如果确实需要模拟异步加载,建议添加 loading 状态展示
89-93
: 建议改进类型定义事件处理函数使用了
any
类型,建议使用更具体的类型定义来提高代码的类型安全性:-const onChange = (value: any, path: any) => { +const onChange = (value: string[], path: CascaderOption[]) => { setValue(value) } -const onPathChange = (value: any, path: any) => { +const onPathChange = (value: string[], path: CascaderOption[]) => { console.log('onPathChange', value, path) }src/packages/cascader/demos/taro/demo7.tsx (2)
12-79
: 建议优化数据加载和数据结构定义
- 建议将选项数据结构提取为单独的常量,提高代码可维护性
- 模拟异步加载可以考虑使用更现代的方式,如
Promise
或async/await
建议重构为:
const ADDRESS_OPTIONS: CascaderOption[] = [ { value: '浙江', text: '浙江', children: [ // ... existing options ], }, // ... other provinces ]; // In component: useEffect(() => { const loadOptions = async () => { setValue(['浙江', '温州', '鹿城区']); setOptions(ADDRESS_OPTIONS); }; loadOptions(); }, []);
80-108
: 建议优化事件处理器并移除调试代码
- 需要移除
onPathChange
中的 console.log- 组件结构和事件处理设计合理
建议修改:
- onPathChange={(value, path) => { - console.log(value, path) - }} + onPathChange={(value, path) => { + // 根据需要处理路径变化 + }}src/packages/cascader/demos/taro/demo6.tsx (2)
19-21
: 建议将初始值提取为常量为了提高代码的可维护性和重用性,建议将初始值提取为一个命名常量。
+const INITIAL_VALUE = ['浙江', '温州', '鹿城区'] const Demo6 = () => { const [visible, setVisible] = useState(false) - const [value, setValue] = useState<string[]>(['浙江', '温州', '鹿城区']) + const [value, setValue] = useState<string[]>(INITIAL_VALUE) const [options, setOptions] = useState<CascaderOption[]>([])
106-112
: 建议在UI中展示加载状态为了提升用户体验,建议将加载状态传递给 Cascader 组件。
<Cascader visible={visible} activeColor="#3768FA" value={value} title="选择地址" options={options} + loading={loading} closeable
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/packages/cascader/demos/h5/demo6.tsx
(3 hunks)src/packages/cascader/demos/taro/demo6.tsx
(3 hunks)src/packages/cascader/demos/taro/demo7.tsx
(1 hunks)src/packages/cascader/doc.taro.md
(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build
🔇 Additional comments (8)
src/packages/cascader/doc.taro.md (1)
23-31
: 文档结构清晰,示例引用正确!新增的非受控用法部分结构合理,与文档风格保持一致。
src/packages/cascader/demos/h5/demo6.tsx (4)
Line range hint
1-21
: 代码结构优化得当!状态变量的命名更加规范,类型定义更加明确,这样的改动提高了代码的可维护性。
34-68
: 注意数据重复问题选项数据中存在重复的城市和区域名称:
- "西湖区" 和 "余杭区" 在杭州和长沙下都出现
- "温州" 在浙江和湖南下都出现
这可能会导致用户混淆,建议使用更真实的示例数据。
Line range hint
95-104
: 单元格组件实现合理!空值处理得当,点击事件处理简洁明了。
105-119
: 级联选择器配置完善!组件属性设置合理,自定义主题色彩运用得当,事件绑定完整。
src/packages/cascader/demos/taro/demo7.tsx (1)
1-7
: 代码结构清晰,类型定义完整!组件的基础架构和状态管理设置合理。
src/packages/cascader/demos/taro/demo6.tsx (2)
24-86
: 建议将选项数据提取到单独的文件中当前选项数据结构在组件中占用了大量空间,建议将其提取到单独的文件中以提高可维护性。
建议创建
src/packages/cascader/demos/taro/mock-data.ts
文件:export const cascaderOptions: CascaderOption[] = [ { value: '浙江', text: '浙江', children: [ // ... 现有选项数据 ] }, // ... 其他省份数据 ]
22-88
: 🛠️ Refactor suggestion建议添加错误处理和加载状态
异步加载数据时应该添加适当的错误处理机制和加载状态指示。
+ const [loading, setLoading] = useState(false) useEffect(() => { + setLoading(true) setTimeout(() => { setOptions([ // ... ]) + setLoading(false) + }, 300).catch((error) => { + console.error('加载选项失败:', error) + setLoading(false) }) }, [])Likely invalid or redundant comment.
const onChange = (value: any, path: any) => { | ||
console.log('onchange', value, path) | ||
setValue(value) | ||
} |
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
建议改进类型定义和移除调试代码
- 应该避免使用
any
类型,建议使用具体的类型定义 - 生产环境代码中不应该保留 console.log
建议按如下方式修改:
- const onChange = (value: any, path: any) => {
- console.log('onchange', value, path)
+ const onChange = (value: string[], path: CascaderOption[]) => {
setValue(value)
}
Committable suggestion skipped: line range outside the PR's diff.
🤔 这个变动的性质是?
🔗 相关 Issue
💡 需求背景和解决方案
Summary by CodeRabbit
发布说明
新功能
改进
文档更新
测试