-
Notifications
You must be signed in to change notification settings - Fork 271
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: picker #2990
base: feat_v3.x
Are you sure you want to change the base?
refactor: picker #2990
Conversation
…react into feat_v3.x_picker
Walkthrough这次更新主要围绕配置和类型重构展开。配置文件中将多个组件的“dd”属性由 false 改为 true,并更新了 Picker 组件的 author,同时新增了 PickerView。各 DatePicker、Picker 及表单相关模块全面替换旧的 PickerOption 类型为更明确的 PickerOptionItem 和 PickerValue,同时将属性名称从 text 调整为 label。组件测试、演示示例和样式文件也进行了相应修改,部分老旧组件如 PickerPanel 被移除,导出接口也做了相应精简和更新。 Changes
Sequence Diagram(s)DatePicker onConfirm FlowsequenceDiagram
participant User as 用户
participant DP as DatePicker 组件
participant Parent as 父组件
User->>DP: 选择日期(使用 label 显示选项)
DP->>DP: 内部状态更新为 PickerValue[] 与 PickerOptionItem[]
DP->>Parent: 调用 onConfirm(selectedOptions, selectedValue)
Parent-->>User: 更新显示选择的日期
Picker onConfirm FlowsequenceDiagram
participant User as 用户
participant P as Picker 组件
participant Parent as 父组件
User->>P: 选择 Picker 选项(新数据结构)
P->>P: 更新内部分层状态与值(使用 label)
P->>Parent: 触发 onConfirm(selectedOptions, selectedValue)
Parent-->>User: 返回更新后的选项
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (2)
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: 14
🧹 Nitpick comments (65)
src/packages/picker/demos/taro/demo2.tsx (1)
11-11
: 建议增强选项数组的类型安全性虽然选项数组的结构改进很好,但建议添加明确的类型定义以提高代码的可维护性。
建议应用以下更改:
- const options = [ + const options: PickerOptions = [ [ { value: 1, label: '南京市' }, // ... other options ], ]Also applies to: 13-25
src/packages/pickerview/demos/taro/demo7.tsx (1)
5-23
: 建议优化数据加载的用户体验当前实现存在以下可以改进的地方:
- 缺少加载状态的管理,用户无法知道数据正在加载
- 没有错误处理机制
- 使用固定的3秒延迟不够灵活
建议按照以下方式优化:
const Demo7 = () => { + const [loading, setLoading] = useState(true) const [columnsList, setColumnsList] = useState([] as PickerOptions[]) + const [error, setError] = useState<Error | null>(null) useEffect(() => { + setLoading(true) + setError(null) setTimeout(() => { - setColumnsList([ - [ - { value: 1, label: '南京市' }, - // ...其他城市 - ], - ]) + try { + setColumnsList([ + [ + { value: 1, label: '南京市' }, + // ...其他城市 + ], + ]) + } catch (err) { + setError(err instanceof Error ? err : new Error('未知错误')) + } finally { + setLoading(false) + } }, 3000) }, [])src/packages/picker/picker.tsx (1)
35-35
: 可定制标签渲染
通过renderLabel
回调让用户自定义选项文案,扩展性很好。src/packages/pickerview/pickerview.taro.tsx (2)
87-87
: 建议使用可选链运算符以提升可读性及避免潜在空引用问题。
当前通过while (columnOptions && columnOptions.children)
判断可能被静态分析工具视为可以用可选链替换。虽然现有实现并不会导致严重错误,但可选链有助于提升代码可读性并减少潜在空值风险。以下为可能的代码修改示例:
- while (columnOptions && columnOptions.children) { + while (columnOptions?.children) { const currentOptions: PickerOptions = columnOptions.children ... }
110-110
: 减少对(touch as any)
的依赖。
在此处使用(touch as any).isVertical
虽然可以工作,但会降低类型安全性。建议在useTouch
自定义 Hook 中完善返回值的类型定义,以免在此处使用any
。src/packages/pickerview/pickerroller.tsx (3)
5-6
: 谨慎使用ForwardRefRenderFunction
与不完整类型定义。
此处的泛型声明中Partial<PickerRollerProps>
虽然更灵活,但也可能使得必传属性意外缺失。建议确保类型与业务使用场景一致,以避免后期对属性的错误调用。
31-31
: 建议对滚动惯性与距离做进一步可配置。
INERTIA_TIME 与 INERTIA_DISTANCE 的常量对交互有较大影响,后续若需要针对多种 UI 或设备场景做细微调整,可将其提取并抽离成可配置项,以提升扩展性。
37-37
: 考虑将useRef<any>
替换为更明确的类型。
useRef<any>
也降低了类型检查的有效性,特别是对 DOM 对象和自定义对象的操作时,建议使用合适的类型或HTMLDivElement | null
等更精确的定义,从而在编译期捕获潜在错误。Also applies to: 86-86
src/packages/pickerview/pickerroller.taro.tsx (2)
8-8
: 针对 Taro 环境的条件逻辑可进一步抽象。
通过web()
判断来分支处理,可在后续多平台逻辑扩展时引发重复或分支增多。若后续需兼容更多平台,可将platform-taro
重构为统一的多平台适配层,以减少散落于各处的判断语句。Also applies to: 12-12
38-38
: 建议避免过渡使用any
并确保类型安全。
isMoving
、pickerRollerRef
、rollerRef
等均使用了any
,在多人协作或者日后维护时容易出现逻辑或属性访问错误。可适度扩充类型以提升可维护性。src/packages/pickerview/index.taro.ts (1)
1-11
: 建议优化类型导出的代码复用index.ts 和 index.taro.ts 之间存在类型导出的重复代码。建议考虑创建一个共享的类型导出文件,以减少代码重复并提高可维护性。
+ // src/packages/pickerview/shared-types.ts + export type { + PickerViewProps, + PickerOptionItem, + PickerRollerProps, + PickerValue, + PickerOptions, + PickerOnChangeCallbackParameter, + } from './types' // src/packages/pickerview/index.ts import PickerView from './pickerview' - export type { - PickerViewProps, - PickerOptionItem, - PickerRollerProps, - PickerValue, - PickerOptions, - PickerOnChangeCallbackParameter, - } from './types' + export * from './shared-types' export default PickerView // src/packages/pickerview/index.taro.ts import PickerView from './pickerview.taro' - export type { - PickerViewProps, - PickerOptionItem, - PickerRollerProps, - PickerValue, - PickerOptions, - PickerOnChangeCallbackParameter, - } from './types' + export * from './shared-types' export default PickerViewsrc/packages/pickerview/demos/h5/demo1.tsx (2)
5-17
: 建议将测试数据移至单独文件建议将城市列表数据提取到单独的数据文件中,以提高代码的可维护性和重用性。
+ // src/packages/pickerview/demos/h5/data.ts + export const cityList = [ + [ + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + // ... other cities + ], + ] // src/packages/pickerview/demos/h5/demo1.tsx - const listData = [/*...*/] + import { cityList } from './data'
19-32
: 建议增加更多交互示例当前示例较为基础,建议添加以下功能来展示组件的完整特性:
- 多列选择示例
- 级联选择示例
- 禁用选项示例
- 自定义样式示例
src/packages/pickerview/demos/taro/demo1.tsx (2)
5-17
: 建议优化数据结构的类型定义建议为
listData
添加类型定义,以提高代码的可维护性和类型安全性。+ type PickerOption = { + value: number + label: string + } + - const listData = [ + const listData: PickerOption[][] = [ [ { value: 1, label: '南京市' }, // ... ], ]
25-27
: 建议改进事件处理方式在生产环境中直接使用
console.log
不太合适。建议:
- 移除 console.log 或使用专门的日志服务
- 添加具体的业务处理逻辑
src/packages/pickerview/demos/h5/demo2.tsx (1)
23-23
: 建议将样式配置抽离建议将样式配置抽离到统一的样式配置文件中,以便于维护和复用。
+ // styles/picker.ts + export const PICKER_STYLES = { + itemHeight: '28px', + } // 组件中使用 - style={{ '--nutui-picker-item-height': '28px' }} + style={{ '--nutui-picker-item-height': PICKER_STYLES.itemHeight }}src/packages/pickerview/demos/h5/demo5.tsx (2)
22-30
: 建议添加属性说明注释为了提高代码可读性,建议添加对特殊属性的说明注释,特别是
threeDimensional
和duration
的用途和影响。<PickerView defaultValue={[1]} options={listData} + // 是否开启3D效果 threeDimensional={false} + // 动画持续时间(毫秒) duration={500} onChange={({ value, selectedOptions }) => { console.log('onChange', value, selectedOptions) }} />
27-29
: 建议完善事件处理与其他 demo 类似,建议改进事件处理方式:
- 移除 console.log
- 添加错误处理
- 添加具体的业务逻辑
src/packages/pickerview/demos/taro/demo5.tsx (2)
27-29
: 建议移除生产环境中的 console.log在生产环境中保留 console.log 语句可能会影响性能并暴露敏感信息。建议使用条件性日志记录或完全移除。
- console.log('onChange', value, selectedOptions) + if (process.env.NODE_ENV !== 'production') { + console.log('onChange', value, selectedOptions) + }
22-30
: 建议添加错误处理和加载状态当前实现缺少错误处理和加载状态的处理机制。
建议添加以下功能:
- 错误边界处理选项加载失败的情况
- 添加加载状态指示器
- 处理空数据的情况
<PickerView defaultValue={[1]} options={listData} threeDimensional={false} duration={500} + loading={isLoading} + onError={(error) => { + console.error('PickerView error:', error) + }} onChange={({ value, selectedOptions }) => {src/packages/pickerview/demos/h5/demo4.tsx (2)
29-31
: 建议优化条件更新逻辑并添加注释当前的条件更新逻辑缺乏清晰的业务含义说明,可能会让其他开发者感到困惑。
+ // 当选择"海北藏族自治区"时,自动切换到"南京市" if (value[0] === 3) { setValue([1]) }
5-17
: 建议将列表数据提取为常量当前的列表数据直接定义在组件内部,建议将其提取为外部常量以提高可重用性。
+const CITY_OPTIONS = [ + [ + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + // ... + ], +] const Demo4 = () => { - const listData = [ - [ - { value: 1, label: '南京市' }, - // ... - ], - ] + const listData = CITY_OPTIONSsrc/packages/pickerview/utils.ts (2)
1-4
: 建议添加注释说明动量计算逻辑momentum 函数中的魔法数字 0.003 缺乏说明,建议添加注释解释计算逻辑。
+/** + * 计算滑动动量 + * @param distance 滑动距离 + * @param duration 滑动持续时间 + * @returns 根据方向调整的速度值 + */ export const momentum = (distance: number, duration: number) => { const speed = Math.abs(distance / duration) + // 0.003 是经验值,用于调整滑动的灵敏度 return (speed / 0.003) * (distance < 0 ? -1 : 1) }
24-28
: 建议优化 3D 变换计算的可读性rollerStyle 函数中的 3D 变换计算较为复杂,建议提取常量并添加注释。
+ // 3D 效果的深度系数 + const DEPTH_FACTOR = 3.2 + const rollerStyle = (index: number) => ({ transform: `rotate3d(1, 0, 0, ${-rotation * (index + 1)}deg) translate3d(0px, 0px, ${Math.round( - lineSpacing.current * 3.2 + lineSpacing.current * DEPTH_FACTOR )}px)`, })src/packages/datepicker/demos/h5/demo2.tsx (1)
16-19
: 建议移除生产环境中的调试代码
console.log
语句通常用于开发调试,建议在提交前移除或使用条件性日志记录。const confirm = (values: PickerValue[], options: PickerOptionItem[]) => { - console.log('values', values, options) setDesc(options.map((option) => option.label).join('-')) }
src/packages/pickerview/demos/h5/demo7.tsx (2)
7-23
: 建议改进异步数据加载的实现当前实现存在以下可以改进的地方:
- 使用固定的延时可能不是最佳实践
- 缺少加载状态的处理
- 缺少错误处理机制
建议添加加载状态和错误处理。
const Demo7 = () => { const [columnsList, setColumnsList] = useState([] as PickerOptions[]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState<Error | null>(null) useEffect(() => { + setLoading(true) + setError(null) setTimeout(() => { - setColumnsList([ - [ - { value: 1, label: '南京市' }, - // ... other cities - ], - ]) + try { + setColumnsList([ + [ + { value: 1, label: '南京市' }, + // ... other cities + ], + ]) + } catch (err) { + setError(err instanceof Error ? err : new Error('Unknown error')) + } finally { + setLoading(false) + } }, 3000) }, [])
30-32
: 建议移除或优化控制台日志在生产环境中应该移除
console.log
语句,或使用专门的日志工具。onChange={({ value, selectedOptions }) => { - console.log('onChange', value, selectedOptions) }}
src/packages/pickerview/demos/h5/demo3.tsx (1)
28-33
: 建议优化值比较和更新逻辑当前实现存在以下问题:
- 使用硬编码的值比较不利于维护
- 包含调试日志
- 值更新逻辑可能导致用户困惑
建议将比较值提取为常量,移除调试日志,并考虑添加状态更新的提示。
+const TRIGGER_VALUE = ['Tuesday', 'Afternoon'] +const NEW_VALUE = ['Monday', 'Evening'] onChange={({ value, selectedOptions }) => { - console.log('onChange', value, selectedOptions) - if (isEqual(value, ['Tuesday', 'Afternoon'])) { - setValue(['Monday', 'Evening']) + if (isEqual(value, TRIGGER_VALUE)) { + setValue(NEW_VALUE) + // 可以添加提示信息 } }}src/packages/pickerview/demos/taro/demo3.tsx (1)
3-3
: 建议优化条件判断逻辑
isEqual
用于简单数组比较可能过于复杂,建议使用Array.prototype.join()
进行比较。- 硬编码的值更新逻辑(从
['Tuesday', 'Afternoon']
到['Monday', 'Evening']
)可能会让用户感到困惑,建议添加注释说明此逻辑的用途。- import isEqual from 'react-fast-compare' ... - if (isEqual(value, ['Tuesday', 'Afternoon'])) { + // 演示动态更新选中值的示例 + if (value.join() === ['Tuesday', 'Afternoon'].join()) {Also applies to: 30-32
src/packages/pickerview/types.ts (2)
3-9
: 建议完善类型定义
PickerValue
类型定义可以更严格,建议移除null
类型,使用undefined
代替。PickerOptionItem
接口的children
属性应该明确定义为数组类型。- export type PickerValue = string | number | null + export type PickerValue = string | number | undefined export interface PickerOptionItem { label: string | number value: string | number - children?: PickerOptionItem[] + children: PickerOptionItem[] | undefined }
29-38
: 建议添加属性注释建议为
PickerViewProps
接口的关键属性添加 JSDoc 注释,以提供更好的开发体验。export interface PickerViewProps extends BasicComponent { + /** 设置组件引用 */ setRefs?: (ref: any) => any + /** 选项数据 */ options: PickerOptions[] + /** 当前选中值 */ value?: PickerValue[] + /** 默认选中值 */ defaultValue?: PickerValue[] + /** 是否开启3D效果 */ threeDimensional?: boolean + /** 动画时长,单位ms */ duration?: number | string + /** 自定义选项展示 */ renderLabel: (item: PickerOptionItem) => React.ReactNode + /** 选项改变回调 */ onChange?: (arg0: PickerOnChangeCallbackParameter) => void }src/packages/datepicker/demos/taro/demo5.tsx (1)
17-20
: 建议优化时间格式化处理
- 默认时间描述
10:10
建议使用常量定义。- 日期字符串拼接可能存在安全隐患,建议使用更安全的方式构造日期。
+ const DEFAULT_TIME = '10:10' - const [desc, setDesc] = useState('10:10') + const [desc, setDesc] = useState(DEFAULT_TIME) const confirm = (options: PickerOptionItem[], values: PickerValue[]) => { setDesc(options.map((option) => option.label).join(':')) } - defaultValue={new Date(`${defaultDescription} ${desc}`)} + defaultValue={new Date( + defaultValue.getFullYear(), + defaultValue.getMonth(), + defaultValue.getDate(), + ...desc.split(':').map(Number) + )}Also applies to: 28-28
src/packages/datepicker/demos/h5/demo7.tsx (1)
17-21
: 建议优化命名和时间处理
confirm6
函数名不够直观,建议改为更具描述性的名称。- 时间字符串
10:10:00
的处理方式可以更安全。+ const DEFAULT_TIME_WITH_SECONDS = '10:10:00' - const [desc, setDesc] = useState('10:10:00') + const [desc, setDesc] = useState(DEFAULT_TIME_WITH_SECONDS) - const confirm6 = (values: PickerValue[], options: PickerOptionItem[]) => { + const handleTimeConfirm = (values: PickerValue[], options: PickerOptionItem[]) => { setDesc(options.map((option) => option.label).join(':')) } - onConfirm={(options, values) => confirm6(values, options)} + onConfirm={(options, values) => handleTimeConfirm(values, options)}Also applies to: 31-31
src/packages/picker/demos/h5/demo5.tsx (1)
23-25
: 建议优化类型定义,避免使用any
在
forEach
回调函数中使用any
类型会降低代码的类型安全性。建议使用更具体的类型定义。- options.forEach((option: any) => { + options.forEach((option: { label: string; value: string | number }) => {src/packages/picker/demos/h5/demo2.tsx (1)
26-28
: 建议优化类型定义,避免使用any
在
forEach
回调函数中使用any
类型会降低代码的类型安全性。建议使用更具体的类型定义。- selectedOptions.forEach((option: any) => { + selectedOptions.forEach((option: { label: string; value: string | number }) => {src/packages/picker/demos/taro/demo5.tsx (2)
2-7
: 建议优化导入语句的组织方式当前的多行导入方式可以更简洁。建议合并为一行,提高代码的可读性。
-import { - Picker, - Cell, - PickerOptions, - PickerValue, -} from '@nutui/nutui-react-taro' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react-taro'
28-30
: 建议优化类型定义,避免使用any
在
forEach
回调函数中使用any
类型会降低代码的类型安全性。建议使用更具体的类型定义。- options.forEach((option: any) => { + options.forEach((option: { label: string; value: string | number }) => {src/packages/picker/demos/h5/demo4.tsx (2)
28-28
: 建议移除调试代码生产环境代码中不应该包含
console.log
语句。- console.log('confirmPicker', selectedOptions)
30-32
: 建议优化类型定义和空值处理代码存在以下问题:
- 使用了
any
类型- 可选链操作符使用不当,建议改用空值合并运算符
- selectedOptions.forEach((option: any) => { - option?.label && (description += ` ${option.label}`) + selectedOptions.forEach((option: { label: string; value: string | number }) => { + description += ` ${option.label ?? ''}`src/packages/picker/demos/taro/demo4.tsx (2)
33-33
: 建议移除生产环境中的 console.log在生产环境中保留 console.log 语句可能会影响性能和安全性。
建议使用以下方式处理:
- console.log('confirmPicker', selectedOptions) + if (process.env.NODE_ENV !== 'production') { + console.log('confirmPicker', selectedOptions) + }
35-37
: 建议优化类型定义和空值处理当前的类型定义使用了 any,并且对空值的处理不够严谨。
建议修改为:
- selectedOptions.forEach((option: any) => { - option?.label && (description += ` ${option.label}`) + selectedOptions.forEach((option: PickerOptions[number]) => { + if (option?.label) { + description = description ? `${description} ${option.label}` : option.label + }src/packages/pickerview/demos/h5/demo6.tsx (2)
5-64
: 建议将数据结构抽离到单独的文件中当前的数据结构直接定义在组件中,这降低了代码的可维护性和复用性。
建议创建单独的数据文件,例如
cityData.ts
:// cityData.ts export const listData = [ [ { value: 1, label: '北京', children: [ // ... existing children data ], }, // ... remaining data ], ]然后在组件中导入:
+import { listData } from './cityData' const Demo6 = () => { - const listData = [...]
70-74
: 建议添加错误边界处理当前的 onChange 回调缺少错误处理机制。
建议添加 try-catch 块:
- onChange={({ value, selectedOptions }) => { - console.log('onChange', value, selectedOptions) - }} + onChange={({ value, selectedOptions }) => { + try { + if (process.env.NODE_ENV !== 'production') { + console.log('onChange', value, selectedOptions) + } + // 在这里添加其他必要的数据处理逻辑 + } catch (error) { + console.error('选择器数据处理错误:', error) + } + }}src/packages/pickerview/demo.tsx (1)
12-40
: 建议将翻译文本抽离到独立的语言文件中当前的翻译直接定义在组件中,这不利于维护和扩展。
建议创建独立的语言文件:
// locales/zh-CN.ts export default { title: '基础用法', adjustHeight: '自适应高度', // ... other translations } // locales/en-US.ts export default { title: 'Basic Usage', adjustHeight: 'Adjust Height', // ... other translations }然后在组件中导入:
+import zhCN from './locales/zh-CN' +import enUS from './locales/en-US' +import zhTW from './locales/zh-TW' const PickerViewDemo = () => { const [translated] = useTranslate({ - 'zh-CN': { ... }, - 'en-US': { ... }, - 'zh-TW': { ... }, + 'zh-CN': zhCN, + 'en-US': enUS, + 'zh-TW': zhTW, })src/packages/pickerview/demos/taro/demo6.tsx (1)
72-74
: 建议添加选择值的类型验证当前的 onChange 回调没有对选择值进行类型验证。
建议添加类型验证:
onChange={({ value, selectedOptions }) => { + if (!Array.isArray(value) || value.some(v => typeof v !== 'number')) { + console.error('选择值类型错误') + return + } console.log('onChange', value, selectedOptions) }}src/packages/picker/demos/h5/demo1.tsx (2)
14-26
: 建议添加默认选中值为了提升用户体验,建议添加
defaultValue
属性来设置默认选中的城市。const Demo1 = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') + const defaultValue = [1] // 默认选中南京市 const options = [ [ { value: 1, label: '南京市' }, // ... ], ] return ( <Picker // ... + defaultValue={defaultValue} options={options} /> ) }
27-44
: 优化字符串拼接方式建议使用
Array.map()
和join()
来优化字符串拼接,使代码更简洁易读。const confirmPicker = ( selectedOptions: PickerOptions, selectedValue: PickerValue[] ) => { console.log('confirmPicker', selectedOptions, selectedValue) - let description = '' - selectedOptions.forEach((option: PickerOptionItem) => { - description += ` ${option.label}` - }) + const description = selectedOptions + .map((option: PickerOptionItem) => option.label) + .join(' ') setBaseDesc(description) }src/packages/picker/demos/taro/demo1.tsx (1)
1-64
: 建议提取共享代码H5 和 Taro 的 demo 代码几乎完全相同,建议将共享逻辑提取到一个公共文件中,以减少代码重复。
建议创建一个共享的 hooks 文件:
// src/packages/picker/demos/shared/usePickerDemo.ts import { useState } from 'react' import type { PickerOptions, PickerValue, PickerOnChangeCallbackParameter } from '@nutui/nutui-react' export const usePickerDemo = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') const options = [ [ { value: 1, label: '南京市' }, // ... ], ] const changePicker = (params: PickerOnChangeCallbackParameter) => { console.log('changePicker', params) } const confirmPicker = (selectedOptions: PickerOptions, selectedValue: PickerValue[]) => { // ... } return { visible, setVisible, baseDesc, options, changePicker, confirmPicker, } }然后在 H5 和 Taro 的 demo 中复用这个 hook:
const Demo1 = () => { const { visible, setVisible, baseDesc, options, changePicker, confirmPicker, } = usePickerDemo() return ( // ... ) }src/packages/picker/demos/taro/demo8.tsx (1)
46-62
: 建议提取主题配置建议将主题配置提取到共享的常量文件中,以确保 H5 和 Taro 版本的样式保持一致。
// src/packages/picker/demos/shared/constants.ts export const PICKER_THEME = { nutuiPickerItemHeight: '48px', nutuiPickerItemActiveLineBorder: '1px dashed var(--nutui-color-primary)', nutuiPickerItemTextColor: 'var(--nutui-color-primary)', '--nutui-picker-item-height': '28px', } as const // 在 demo 中使用 <ConfigProvider theme={PICKER_THEME}> <Picker title="请选择城市" // ... /> </ConfigProvider>src/packages/datepicker/demos/h5/demo8.tsx (1)
28-46
: 格式化函数命名可以改进函数名
formatter1
不够具体,建议使用更有描述性的名称。建议重命名为更具描述性的名称:
- const formatter1 = (type: string, option: PickerOptionItem) => { + const appendUnitFormatter = (type: string, option: PickerOptionItem) => {src/packages/datepicker/demos/taro/demo8.tsx (1)
28-46
: 建议优化 formatter 函数的实现当前实现直接修改了传入的 option 对象。建议返回新对象以保持不可变性。
建议如下修改:
const formatter = (type: string, option: PickerOptionItem) => { + const newOption = { ...option } switch (type) { case 'year': - option.label += `年` + newOption.label += `年` break case 'month': - option.label += `月` + newOption.label += `月` break case 'day': - option.label += `日` + newOption.label += `日` break case 'hour': - option.label += `时` + newOption.label += `时` break default: - option.label += '' + newOption.label += '' } - return option + return newOption }src/packages/picker/demos/taro/demo3.tsx (1)
40-50
: 建议优化条件判断逻辑当前实现中硬编码了特定值的判断(
[3]
),这可能导致维护性问题。建议将这些特殊情况的处理提取为配置或常量。建议如下修改:
+ const SPECIAL_CITY = { + value: 3, + defaultValue: 1, + defaultLabel: '南京市' + } if (isEqual(selectedValue, [SPECIAL_CITY.value])) { - setValue([1]) - setBaseDesc('南京市') + setValue([SPECIAL_CITY.defaultValue]) + setBaseDesc(SPECIAL_CITY.defaultLabel) }src/packages/datepicker/demos/taro/demo1.tsx (1)
24-27
: 建议移除多余的空行在
change
函数中存在不必要的空行,影响代码的紧凑性。建议如下修改:
const change = (options: PickerOptionItem[], values: PickerValue[]) => { const v = values.join('/') - setValue(v) setDesc2(options.map((option) => option.label).join(' ')) }
src/packages/datepicker/demos/h5/demo1.tsx (1)
48-48
: 建议移除或优化调试日志生产环境代码中不建议保留 console.log 语句。如果需要日志,建议使用正式的日志系统。
建议如下修改:
- console.log('onconfirm', values, options) + // 如果需要日志,请使用正式的日志系统src/packages/pickerview/demo.taro.tsx (1)
6-12
: 建议为 Demo 组件添加类型定义为了增强代码的类型安全性,建议为导入的 Demo 组件添加明确的类型定义。这样可以在编译时捕获潜在的类型错误。
-import Demo1 from './demos/taro/demo1' +import type { FC } from 'react' +import Demo1 from './demos/taro/demo1' +type DemoComponent = FCsrc/packages/picker/demos/h5/demo6.tsx (1)
73-74
: 建议移除生产环境中的 console.log为了保持代码整洁和性能优化,建议在生产环境中移除 console.log 语句。可以使用环境变量或日志库来控制日志输出。
- console.log('onconfirm', selectedOptions, selectedValue) + if (process.env.NODE_ENV === 'development') { + console.log('onconfirm', selectedOptions, selectedValue) + }Also applies to: 93-95
src/packages/picker/demos/taro/demo7.tsx (1)
87-90
: 建议添加类型注释为了提高代码的可读性和维护性,建议为
selectedOptions
和selectedValue
参数添加显式的类型注释。const setAsyncConfirm = ( - selectedOptions: PickerOptions, - selectedValue: PickerValue[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[], ) => {src/packages/pickerview/__test__/pickerview.spec.tsx (1)
97-103
: 基础渲染测试用例完整。测试用例验证了组件的基本渲染功能和默认值的正确显示。建议添加对错误情况的测试,如无效的 defaultValue。
src/packages/datepicker/datepicker.tsx (1)
410-418
: 回调函数模式可以优化。使用可选链操作符可以简化回调函数的调用。
- onConfirm={(selectedOptions, selectedValue) => onConfirm && onConfirm(selectedOptions, selectedValue)} + onConfirm={(selectedOptions, selectedValue) => onConfirm?.(selectedOptions, selectedValue)}🧰 Tools
🪛 Biome (1.9.4)
[error] 414-414: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/packages/datepicker/datepicker.taro.tsx (2)
415-423
: 回调函数实现需要优化。与非 Taro 版本一样,这里也应该使用可选链操作符来简化代码。
- onConfirm={(selectedOptions, selectedValue) => onConfirm && onConfirm(selectedOptions, selectedValue)} + onConfirm={(selectedOptions, selectedValue) => onConfirm?.(selectedOptions, selectedValue)}🧰 Tools
🪛 Biome (1.9.4)
[error] 419-419: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
1-431
: 代码实现与非 Taro 版本保持一致。良好地保持了两个版本之间的一致性,便于维护。建议考虑提取共同逻辑到共享模块中。
🧰 Tools
🪛 Biome (1.9.4)
[error] 419-419: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/packages/pickerview/pickerview.scss (2)
19-27
: 建议:考虑添加浏览器前缀以提高兼容性对于
background-image
和transform
属性,建议添加浏览器前缀以提高兼容性。&-mask { top: 0; bottom: 0; background-image: $picker-mask-background; background-position: top, bottom; background-size: 100% $pickerview-top; background-repeat: no-repeat; + -webkit-transform: translateZ(0); transform: translateZ(0); }
55-65
: 建议:优化 backface-visibility 的写法可以使用简写方式来减少代码重复。
&-roller-item { position: absolute; top: 0; - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-backface-visibility: hidden; &-hidden { visibility: hidden; opacity: 0; } }src/packages/pickerview/doc.md (1)
1-95
: 文档结构完整,内容清晰文档包含了必要的所有部分:
- 组件说明
- 引入方式
- 示例代码
- Props 定义
- 主题定制说明
建议补充以下内容以使文档更加完善:
- 添加在线预览链接
- 补充更多使用场景示例
- 添加常见问题(FAQ)部分
src/packages/pickerview/doc.zh-TW.md (1)
1-95
: 繁體中文文檔翻譯準確,結構完整文檔的繁體中文翻譯質量很好,與簡體中文版本保持了一致的結構和內容。建議:
- 確保示例代碼中的註釋也翻譯為繁體中文
- 補充針對繁體中文用戶的特定使用說明
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/packages/pickerview/__test__/__snapshots__/pickerview.spec.tsx.snap
is excluded by!**/*.snap
📒 Files selected for processing (78)
src/config.json
(4 hunks)src/packages/datepicker/__test__/datepicker.spec.tsx
(6 hunks)src/packages/datepicker/datepicker.taro.tsx
(9 hunks)src/packages/datepicker/datepicker.tsx
(9 hunks)src/packages/datepicker/demos/h5/demo1.tsx
(3 hunks)src/packages/datepicker/demos/h5/demo2.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo3.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo4.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo5.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo6.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo7.tsx
(2 hunks)src/packages/datepicker/demos/h5/demo8.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo1.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo2.tsx
(1 hunks)src/packages/datepicker/demos/taro/demo3.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo4.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo5.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo6.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo7.tsx
(2 hunks)src/packages/datepicker/demos/taro/demo8.tsx
(2 hunks)src/packages/form/demos/h5/demo7.tsx
(2 hunks)src/packages/form/demos/taro/demo7.tsx
(2 hunks)src/packages/picker/__tests__/picker.spec.tsx
(6 hunks)src/packages/picker/demos/h5/demo1.tsx
(2 hunks)src/packages/picker/demos/h5/demo2.tsx
(1 hunks)src/packages/picker/demos/h5/demo3.tsx
(1 hunks)src/packages/picker/demos/h5/demo4.tsx
(2 hunks)src/packages/picker/demos/h5/demo5.tsx
(2 hunks)src/packages/picker/demos/h5/demo6.tsx
(1 hunks)src/packages/picker/demos/h5/demo7.tsx
(2 hunks)src/packages/picker/demos/h5/demo8.tsx
(2 hunks)src/packages/picker/demos/taro/demo1.tsx
(2 hunks)src/packages/picker/demos/taro/demo2.tsx
(1 hunks)src/packages/picker/demos/taro/demo3.tsx
(1 hunks)src/packages/picker/demos/taro/demo4.tsx
(1 hunks)src/packages/picker/demos/taro/demo5.tsx
(2 hunks)src/packages/picker/demos/taro/demo6.tsx
(1 hunks)src/packages/picker/demos/taro/demo7.tsx
(2 hunks)src/packages/picker/demos/taro/demo8.tsx
(2 hunks)src/packages/picker/index.taro.ts
(0 hunks)src/packages/picker/index.ts
(0 hunks)src/packages/picker/picker.scss
(1 hunks)src/packages/picker/picker.taro.tsx
(6 hunks)src/packages/picker/picker.tsx
(6 hunks)src/packages/picker/pickerpanel.taro.tsx
(0 hunks)src/packages/picker/pickerpanel.tsx
(0 hunks)src/packages/picker/types.ts
(1 hunks)src/packages/pickerview/__test__/pickerview.spec.tsx
(1 hunks)src/packages/pickerview/demo.taro.tsx
(1 hunks)src/packages/pickerview/demo.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo1.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo2.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo3.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo4.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo5.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo6.tsx
(1 hunks)src/packages/pickerview/demos/h5/demo7.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo1.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo2.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo3.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo4.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo5.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo6.tsx
(1 hunks)src/packages/pickerview/demos/taro/demo7.tsx
(1 hunks)src/packages/pickerview/doc.en-US.md
(1 hunks)src/packages/pickerview/doc.md
(1 hunks)src/packages/pickerview/doc.taro.md
(1 hunks)src/packages/pickerview/doc.zh-TW.md
(1 hunks)src/packages/pickerview/index.taro.ts
(1 hunks)src/packages/pickerview/index.ts
(1 hunks)src/packages/pickerview/pickerroller.taro.tsx
(1 hunks)src/packages/pickerview/pickerroller.tsx
(1 hunks)src/packages/pickerview/pickerview.scss
(1 hunks)src/packages/pickerview/pickerview.taro.tsx
(1 hunks)src/packages/pickerview/pickerview.tsx
(1 hunks)src/packages/pickerview/types.ts
(1 hunks)src/packages/pickerview/utils.ts
(1 hunks)src/styles/variables.scss
(1 hunks)
💤 Files with no reviewable changes (4)
- src/packages/picker/index.ts
- src/packages/picker/index.taro.ts
- src/packages/picker/pickerpanel.tsx
- src/packages/picker/pickerpanel.taro.tsx
✅ Files skipped from review due to trivial changes (2)
- src/packages/pickerview/doc.taro.md
- src/packages/pickerview/doc.en-US.md
🧰 Additional context used
🪛 GitHub Actions: CI
src/packages/datepicker/__test__/datepicker.spec.tsx
[error] 45-45: AssertionError: expected +0 to be 3 // Object.is equality
🪛 Biome (1.9.4)
src/packages/pickerview/pickerview.taro.tsx
[error] 88-88: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/packages/pickerview/pickerview.tsx
[error] 87-87: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/packages/datepicker/datepicker.tsx
[error] 414-414: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/packages/datepicker/datepicker.taro.tsx
[error] 419-419: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (112)
src/packages/datepicker/demos/h5/demo5.tsx (2)
2-7
: 导入声明更新符合重构要求!导入声明已更新为使用新的类型定义
PickerOptionItem
和PickerValue
,这与整体重构方向保持一致。
18-19
: 函数签名和实现更新正确!
- 函数参数类型从
PickerOption[]
更新为PickerOptionItem[]
- 属性访问从
text
更改为label
- 实现逻辑保持不变,仅更新了类型和属性名
这些更改与组件重构的目标保持一致。
src/packages/picker/demos/taro/demo2.tsx (2)
2-7
: 导入声明看起来不错!类型导入的更改提高了代码的类型安全性,结构化的导入方式也使代码更加清晰。
38-50
: 组件渲染部分的改动很棒!Cell 和 Picker 组件的属性更新简洁明了,保持了组件功能的同时提高了代码的可读性。
src/packages/pickerview/demos/taro/demo7.tsx (2)
1-4
: 代码结构清晰,导入合理!组件的声明和必要的导入都很规范。
38-38
: 导出语句正确!组件导出方式符合规范。
src/packages/datepicker/demos/h5/demo4.tsx (1)
2-7
: 导入更改看起来不错!新增的类型导入使代码更加类型安全,结构清晰。
src/packages/picker/picker.tsx (25)
9-19
: 引入新依赖与类型定义的变更不错
这些 import 统一了 Picker 相关类型,并使用react-fast-compare
做深度比较,有助于避免复杂对象不必要的重新渲染,整体设计看起来良好。
24-24
: 补充导入PickerActions
与PickerRef
在同一处为外部使用场景提供类型推断,明确了组件的引用方式,合理。
29-31
: 改用PickerOptions[]
与PickerValue[]
类型
使用更准确的类型定义有助于代码的可读性和类型安全,符合预期的重构目标。
41-42
: 确认回调中的数据类型
selectedOptions
声明为PickerOptions
,但内部可能是多列或级联数据,需确保类型定义与实际选项结构保持一致。
46-47
: 关闭回调的参数保持一致
与 onConfirm 相同的参数结构,维持了统一性,无明显问题。
49-49
:onChange
属性更符合语义
增加回调类型PickerOnChangeCallbackParameter
,可让外部准确获取变更信息,设计合理。
54-54
: 默认标题为空字符串
允许在不提供标题时保持界面简洁,可行。
57-57
: 默认value
未定义
结合非受控用法,方便在无默认值时让组件自行管理状态,设计合理。
86-86
: 使用usePropsValue
管理受控/非受控
能统一处理 visible、value 等属性,简化外部与内部状态的同步,思路巧妙。
90-91
: 在onChange
回调中触发onConfirm
需确保交互合理
此处onChange
直接调用props.onConfirm
,可能在尚未点击“确认”时就触发提交逻辑,建议确认该行为符合业务需求。
94-103
: 关闭弹窗时自动触发onClose
结合usePropsValue
实现自动监听,逻辑清晰。
115-115
: 通过解构初始值为新数组
能够避免引用陷阱,初始化内部状态正确。
116-116
: 引入innerValueRef
在回调中读取最新状态,无需重新渲染,常见且实用的模式。
117-117
: 内部选项初始为空数组
确保组件首次渲染时有初始可用状态,逻辑简单。
118-118
: 使用selectedOptionsRef
可在内部存储选中的选项对象或列表,避免重复计算,实践良好。
119-119
: 自定义useRefs
满足同时跟踪多个滚动实例等需求,针对性强。
123-126
: 在useEffect
中更新内部值与选项
当innerVisible
为真时初始化状态,不存在直接逻辑问题,但需留意依赖中包含innerOptions
是否导致多次渲染循环。
128-128
: 重复依赖项
此处仅重复说明依赖范围,忽略即可。
129-145
: 分发回调与内部状态同步
内置防抖逻辑isEqual
避免重复调用,更新后再通知外部的做法可减少多余渲染。
147-147
: 确认事件函数封装
通过onConfirmEvent
有效分离业务逻辑,便于维护。
153-153
: 防止滚轮动画时提前触发确认
校验moving
并在滚动结束后再执行保存流程,交互体验更友好。
159-163
: 取消事件恢复状态
取消时重置innerValue
并隐藏弹窗,符合直觉的交互逻辑。
191-214
: 封装渲染逻辑
将 Picker 视图单独提取到renderPickerElement
,有效提高可读性与可维护性。
218-230
: 结合Popup
+SafeArea
移动端场景友好,自动适配底部安全区域,合理。
236-236
: 最终导出 Ref
React.forwardRef
能为外部提供触发开关等功能,便于集成。src/packages/pickerview/pickerview.tsx (15)
1-19
: 新增组件的基础导入
全面引入 React Hooks、第三方库与自定义类型,有利于拆分逻辑;react-fast-compare
用于深度比较以减少无效更新,思路良好。
21-27
: 默认属性设计
defaultValue
与renderLabel
等默认为空或简单函数,使组件具有良好的开箱即用体验。
29-32
: 前向引用支持
通过React.forwardRef
统一管理组件实例,增加拓展性。
33-43
: 解构与合并默认属性
使用{ ...defaultProps, ...props }
整合用户与默认配置,简洁直观,但要确认对所有字段都适用。
45-55
: 内部状态管理和多列的初始值
利用usePropsValue
同时支持受控/非受控模式,存储选中的各列值,实践规范。
57-70
: 多列或级联的类型判断
columnsType
区分了两种类型的选项,写法直观利于后续处理。
72-107
:formatCascadeOptions
处理级联数据
通过循环与 children 逐级展开选项,逻辑完善,返回多列结构便于渲染。🧰 Tools
🪛 Biome (1.9.4)
[error] 87-87: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
109-117
:formatOptions
综合处理多列或级联
结合columnsType
动态生成最终选项结构,代码可维护性高。
119-125
: 在依赖更新时重置内部选项
若外部传入新options
,则重新计算innerOptions
保持组件同步,逻辑正确。
126-131
: 跟踪并同步外部选中值
稳定地监听selectedValue
变化,保证内部与外部状态一致。
132-173
:handleSelect
分步更新逻辑
分别针对多列和级联编排选项与值,分支逻辑清晰,层次分明。
175-185
: 推导已选 Options
利用innerOptions
与innerValue
匹配得到已选项,提供给父组件更直观的数据。
187-193
: 变化后通知外部
在useEffect
内合并当前选择并调用onChange
,及时同步信息。
195-217
: 核心渲染结构
循环生成多列 PickerRoller,并在有数据时渲染 mask、indicator,布局逻辑完整。
220-224
: 最终导出PickerView
通过 forwardRef 输出,方便外部控制滚动逻辑或获取内部引用,无可见问题。src/packages/picker/picker.taro.tsx (22)
8-10
: 引入 Taro 原生组件与比较函数
View
组件搭配react-fast-compare
深度判断,为小程序环境提供合适支持。
11-20
: 添加 Taro 端 Picker 相关依赖
@nutui/nutui-react-taro
中的类型统一,保证跨端一致性,值得肯定。
25-25
: 补充导入PickerActions
与PickerRef
提高复用性并清晰标明组件可用方法,设计合理。
30-32
: 将选项与选中值声明为泛型数组
为多列或级联选项打下类型基础,避免类型不匹配。
36-36
: 自定义标签渲染
renderLabel
扩展性高,可自定义显示逻辑,方便满足多种需求。
42-43
:onConfirm
类型定义
同样传入选项与选中的值,保持与picker.tsx
一致性,使用起来更自然。
46-47
:onClose
回调传入相同数据
可在关闭时获取当前状态,逻辑与 Web 端一致。
50-50
: 变更回调参数同样统一
精准传递PickerOnChangeCallbackParameter
,增强可维护性。
58-58
: 默认value
为undefined
方便区分受控和非受控模式,贯彻统一设计。
63-63
: 前向引用的整体封装
确保小程序端也能调用外部方法,复用逻辑与 Web 端相同。
87-87
:usePropsValue
同步管理
可减少手动维护特性分支,利于组件内外完整交互。
91-92
: 在onChange
中直接触发onConfirm
同 Web 端存在的类似疑惑,需确认该流程是否符合 UI 预期,避免过早提交数据。
99-103
: 关闭回调触发
与 Web 端统一逻辑:组件关闭后可获取最终或取消状态,简单直观。
116-120
: 内部状态与引用
保留innerValueRef
、innerOptions
、selectedOptionsRef
等,便于滚动动画、级联更新。
124-127
: 在弹窗可见时重置内部状态
与 Web 端做法一致,显式设置当前值与选项,避免旧数据残留。
129-145
:onChangeItem
差异更新
仅当新旧值不同才触发更新与回调,能减少重复渲染或多余操作。
148-153
: 确认事件检查滚动状态
等待滚动停止后再应用选中值,交互更自然,功能匹配 Web 端。
154-154
: 无滚动时即更新外部状态并收起
与前端逻辑对齐,完整关闭流程合理。
159-163
: 取消事件回退至原有值
整体用户体验可控,与 onCancel 语义对齐。
193-214
: 分离核心渲染
renderPickerElement
函数封装布局逻辑,与业务事件分离,维护更轻松。
220-230
: 窗口与底部安全区适配
小程序端同样使用Popup
与SafeArea
,满足跨端一致体验。
238-238
: 最终通过 forwardRef 导出
呼应上方InternalPicker
,保持组件的可复用性和一致性。src/packages/pickerview/pickerview.taro.tsx (1)
79-79
: 检查滚动计算与索引转换逻辑的正确性。
handleMove
函数中使用Math.round(updatedMove / lineSpacing.current)
去确定索引时,要确保lineSpacing
与currentIndex
的默认值和增量逻辑彼此配合良好,避免出现 off-by-one 错误或小数精度失误。当前实现看上去可行,但依赖36px
行高及 “+1” 偏移,若将来视觉样式或需求改动,则需要同步修正本段逻辑。Also applies to: 95-95
src/packages/pickerview/pickerroller.taro.tsx (1)
151-158
: 通过 CSS 变量获取高度时,请注意异常场景。
若获取不到--nutui-picker-item-height
或解析失败,代码会跳过对lineSpacing.current
的更新,可能导致滚动行为异常。建议补充对获取不到或转换失败时的兼容处理,并记录告警日志。src/packages/picker/types.ts (2)
1-6
: 类型定义清晰且实用!
PickerRef
和PickerActions
类型的定义为组件提供了良好的编程接口,使开发者能够通过引用来控制选择器的开关状态。
6-6
: 类型定义完善且具有扩展性!
ColumnsType
类型很好地定义了选择器的三种模式:单选、多选和级联,为后续功能扩展提供了良好的基础。src/packages/pickerview/index.ts (1)
1-11
: 导出结构规范且完整!入口文件清晰地导出了 PickerView 组件及其相关类型,方便使用者按需引入。类型导出的组织方式符合最佳实践。
src/packages/datepicker/demos/taro/demo2.tsx (2)
2-7
: 导入声明更新符合新的类型系统导入声明已更新为使用新的
PickerOptionItem
和PickerValue
类型,这与组件重构的方向一致。
15-17
: 类型定义和属性访问更新正确函数签名已更新为使用
PickerValue
和PickerOptionItem
类型,同时将text
属性更改为label
,保持了与整体重构的一致性。src/packages/datepicker/demos/taro/demo7.tsx (2)
2-7
: 导入声明更新符合重构要求导入声明已更新为使用新的类型定义,这与组件的重构保持一致。
19-20
: 类型定义和实现更新正确函数签名和实现已更新为使用
PickerValue
和PickerOptionItem
类型,并正确使用了label
属性。src/packages/datepicker/demos/taro/demo4.tsx (2)
2-7
: 导入声明更新保持一致导入声明的更新与其他演示文件保持一致,符合重构规范。
18-19
: 类型和实现更新符合预期
confirm
函数的参数类型和实现更新正确,使用了新的类型定义和属性名称。src/packages/datepicker/demos/h5/demo3.tsx (2)
2-7
: H5版本导入声明更新正确H5版本的导入声明已正确更新,使用了新的类型定义。
19-23
: 日期时间处理逻辑保持不变虽然更新了类型定义,但保持了原有的日期和时间处理逻辑,这是正确的做法。
src/packages/datepicker/demos/taro/demo3.tsx (2)
2-7
: Taro版本导入声明更新正确Taro版本的导入声明已正确更新,与H5版本保持一致性。
19-23
: 日期时间处理逻辑与H5版本一致更新后的实现保持了与H5版本相同的日期时间处理逻辑,确保了跨平台的一致性。
src/packages/picker/demos/h5/demo5.tsx (1)
38-40
: 代码结构优化良好
- 使用了新的类型定义
- 属性从
text
更新为label
- 回调函数直接传递,避免了不必要的包装
src/packages/picker/demos/h5/demo2.tsx (1)
41-44
: 代码结构优化良好
- Props 结构清晰
- 使用了新的类型定义
- 回调函数直接传递,提高了代码可读性
src/packages/picker/demos/h5/demo4.tsx (1)
43-48
: 代码结构优化良好
- Props 结构清晰
- 使用了新的类型定义
- 状态管理逻辑合理
src/packages/picker/demos/h5/demo1.tsx (1)
2-9
: 类型定义更新得当!引入了更具体的类型定义(
PickerOptions
、PickerValue
、PickerOnChangeCallbackParameter
、PickerOptionItem
),提高了代码的类型安全性。src/packages/picker/demos/h5/demo8.tsx (1)
46-62
: 注意样式优先级冲突
Picker
组件同时使用了ConfigProvider
的主题配置和内联样式,这可能导致样式优先级冲突。建议统一使用ConfigProvider
进行样式配置。<ConfigProvider theme={{ nutuiPickerItemHeight: '48px', nutuiPickerItemActiveLineBorder: '1px dashed var(--nutui-color-primary)', nutuiPickerItemTextColor: 'var(--nutui-color-primary)', + '--nutui-picker-item-height': '28px', }} > <Picker - style={{ '--nutui-picker-item-height': '28px' }} title="请选择城市" // ... /> </ConfigProvider>src/packages/datepicker/demos/h5/demo6.tsx (3)
2-7
: 导入类型声明看起来不错!类型导入清晰明确,符合重构要求。
17-27
: 确认函数的实现符合预期函数参数类型和属性访问已正确更新,保持了一致性。
28-49
: 格式化函数实现正确格式化函数的类型定义和实现都已正确更新,保持了一致性。
src/packages/datepicker/demos/taro/demo6.tsx (1)
2-7
: Taro版本的导入声明同样正确类型导入和H5版本保持一致,符合重构要求。
src/packages/picker/demos/h5/demo3.tsx (2)
3-4
: 新增的依赖引入合理使用 react-fast-compare 进行值比较是个好的做法。
24-30
: 新增的changePicker函数实现简单明了函数实现清晰,参数类型定义准确。
src/packages/datepicker/demos/h5/demo8.tsx (2)
19-21
: 确认函数实现简洁有效使用map和join处理选项数组的方式很优雅。
22-27
: 过滤函数实现正确且实用过滤函数的实现符合业务需求,类型定义准确。
src/packages/datepicker/demos/taro/demo8.tsx (1)
19-21
: 类型更新正确实施!确认函数的类型签名已正确更新为
PickerValue[]
和PickerOptionItem[]
,并且正确使用了label
属性。src/packages/picker/demos/taro/demo7.tsx (3)
2-8
: 导入类型定义增强了类型安全性!新增的类型导入使代码更加类型安全,这是一个很好的改进。
12-13
: 状态管理得到了改进!使用
PickerValue[]
类型替代字符串类型,提高了类型安全性。
53-57
: 回调函数参数使用了类型定义!使用
PickerOnChangeCallbackParameter
类型定义回调函数参数,这是一个很好的实践。src/packages/form/demos/h5/demo7.tsx (1)
20-27
: 选项数据结构得到统一!将
text
属性更改为label
使数据结构更加统一和标准化。src/packages/form/demos/taro/demo7.tsx (1)
21-28
: 跨平台保持一致性!Taro 版本的选项数据结构与 H5 版本保持一致,这是很好的实践。
src/packages/datepicker/__test__/datepicker.spec.tsx (1)
94-115
: 格式化函数更新了属性名称!格式化函数现在正确地使用
label
属性而不是text
,保持了一致性。src/packages/pickerview/__test__/pickerview.spec.tsx (1)
7-19
: 测试数据结构清晰且覆盖了常见场景。测试数据包含了单列、多列和级联数据的情况,有助于全面测试组件功能。
src/packages/picker/__tests__/picker.spec.tsx (2)
12-18
: 接口定义更新合理。将
text
属性更新为label
使接口更符合常见命名规范。
20-28
: 测试数据结构优化。将
simpleColumns
包装在数组中提高了数据结构的一致性,便于处理多列场景。src/packages/datepicker/datepicker.tsx (1)
42-44
: 类型定义更新提升了类型安全性。将
formatter
和filter
函数的参数类型更新为PickerOptionItem
增强了类型检查。src/packages/picker/picker.scss (1)
11-14
: 优化:样式属性的更新提高了布局的可预测性添加
box-sizing: border-box
是一个很好的改进,这样可以使元素的尺寸计算更加直观和可预测。同时使用 CSS 变量($popup-title-height
和$popup-title-font-size
)提高了样式的可维护性。src/packages/pickerview/pickerview.scss (1)
1-9
: 良好实践:使用 CSS 变量和合理的布局结构组件样式结构清晰,使用 CSS 变量(
--nutui-picker-item-height
)便于主题定制,同时合理使用position: relative
和overflow: hidden
控制布局。src/config.json (1)
690-704
: 配置更新符合重构要求配置文件的更新合理:
- 将 Picker 组件的
dd
属性更新为true
- 添加了新的 PickerView 组件配置
- 作者信息更新为 "songsong"
建议:
- 考虑为 PickerView 组件添加更详细的描述信息
- 确保版本号与重构范围相匹配
src/styles/variables.scss (1)
564-565
: 优化:Picker 组件变量定义更加灵活!通过引入
$picker-item-height
变量并基于此计算$picker-list-height
,使得组件更易维护和定制。这种方式:
- 确保了列表高度与项目高度的一致性
- 简化了后续对高度的调整
const confirmPicker = ( | ||
options: PickerOption[], | ||
values: (string | number)[] | ||
selectedOptions: PickerOptions, | ||
selectedValue: PickerValue[] | ||
) => { | ||
let description = '' | ||
options.forEach((option: any) => { | ||
description += ` ${option.text}` | ||
selectedOptions.forEach((option: any) => { | ||
description += ` ${option.label}` | ||
}) | ||
setbaseDefault(description) | ||
setBaseDesc(description) | ||
} |
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 类型
confirmPicker 函数的类型签名改进很好,但在 forEach 回调中使用 any 类型会降低类型安全性。
建议应用以下更改:
- selectedOptions.forEach((option: any) => {
+ selectedOptions.forEach((option: { label: string }) => {
description += ` ${option.label}`
})
📝 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.
const confirmPicker = ( | |
options: PickerOption[], | |
values: (string | number)[] | |
selectedOptions: PickerOptions, | |
selectedValue: PickerValue[] | |
) => { | |
let description = '' | |
options.forEach((option: any) => { | |
description += ` ${option.text}` | |
selectedOptions.forEach((option: any) => { | |
description += ` ${option.label}` | |
}) | |
setbaseDefault(description) | |
setBaseDesc(description) | |
} | |
const confirmPicker = ( | |
selectedOptions: PickerOptions, | |
selectedValue: PickerValue[] | |
) => { | |
let description = '' | |
selectedOptions.forEach((option: { label: string }) => { | |
description += ` ${option.label}` | |
}) | |
setBaseDesc(description) | |
} |
return ( | ||
<> | ||
<Cell> | ||
<PickerView | ||
defaultValue={[5]} | ||
options={columnsList} | ||
onChange={({ value, selectedOptions }) => { | ||
console.log('onChange', value, selectedOptions) | ||
}} | ||
/> | ||
</Cell> | ||
</> | ||
) | ||
} |
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
建议完善组件渲染逻辑
- 控制台日志不应该在生产环境使用
- 需要添加加载状态和错误状态的展示
建议按照以下方式修改:
return (
<>
<Cell>
+ {loading && <div>加载中...</div>}
+ {error && <div>错误:{error.message}</div>}
+ {!loading && !error && (
<PickerView
defaultValue={[5]}
options={columnsList}
onChange={({ value, selectedOptions }) => {
- console.log('onChange', value, selectedOptions)
+ // 在这里处理选择变更
}}
/>
+ )}
</Cell>
</>
)
📝 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.
return ( | |
<> | |
<Cell> | |
<PickerView | |
defaultValue={[5]} | |
options={columnsList} | |
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
/> | |
</Cell> | |
</> | |
) | |
} | |
return ( | |
<> | |
<Cell> | |
{loading && <div>加载中...</div>} | |
{error && <div>错误:{error.message}</div>} | |
{!loading && !error && ( | |
<PickerView | |
defaultValue={[5]} | |
options={columnsList} | |
onChange={({ value, selectedOptions }) => { | |
// 在这里处理选择变更 | |
}} | |
/> | |
)} | |
</Cell> | |
</> | |
) | |
} |
const confirm = (values: PickerValue[], options: PickerOptionItem[]) => { | ||
setDesc(options.map((option) => option.label).join(':')) |
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.
💡 Verification agent
🧩 Analysis chain
函数签名和实现的更改符合重构方向!
参数类型的更新提高了类型安全性,使用 label
替代 text
使API更加统一。
建议验证其他使用此组件的地方是否都已更新到新的API:
🏁 Script executed:
#!/bin/bash
# 搜索可能还在使用旧的 text 属性的地方
rg "option\.text" src/
Length of output: 836
请注意:部分文件仍在使用旧 API (option.text
)
当前文件 src/packages/datepicker/demos/h5/demo4.tsx
的修改正确地将属性由 text
更新为 label
且提升了类型安全性。但全局搜索显示,以下文件中仍有对 option.text
的引用:
src/packages/calendar/demos/h5/demo6.tsx
src/packages/calendar/demos/taro/demo6.tsx
src/packages/popover/demos/taro/demo4.tsx
src/packages/popover/demos/taro/demo4-1.tsx
src/packages/popover/demos/h5/demo4.tsx
src/packages/popover/demos/h5/demo4-1.tsx
建议检查并统一更新这些文件以确保 API 的一致性。可使用如下命令进一步确认相关引用:
#!/bin/bash
rg "option\.text" src/
onChange={({ value, selectedOptions }) => { | ||
console.log('onChange', value, selectedOptions) | ||
}} |
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
建议完善错误处理和移除控制台日志
- 建议添加错误处理逻辑
- 在生产环境中应移除 console.log
onChange={({ value, selectedOptions }) => {
- console.log('onChange', value, selectedOptions)
+ try {
+ // 处理选择变更
+ if (process.env.NODE_ENV === 'development') {
+ console.log('onChange', value, selectedOptions)
+ }
+ } catch (error) {
+ // 错误处理逻辑
+ }
}}
📝 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.
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
onChange={({ value, selectedOptions }) => { | |
try { | |
// 处理选择变更 | |
if (process.env.NODE_ENV === 'development') { | |
console.log('onChange', value, selectedOptions) | |
} | |
} catch (error) { | |
// 错误处理逻辑 | |
} | |
}} |
import React from 'react' | ||
import { PickerView, Cell } from '@nutui/nutui-react-taro' | ||
|
||
const Demo2 = () => { | ||
const listData = [ | ||
[ | ||
{ value: 1, label: '南京市' }, | ||
{ value: 2, label: '无锡市' }, | ||
{ value: 3, label: '海北藏族自治区' }, | ||
{ value: 4, label: '北京市' }, | ||
{ value: 5, label: '连云港市' }, | ||
{ value: 8, label: '大庆市' }, | ||
{ value: 9, label: '绥化市' }, | ||
{ value: 10, label: '潍坊市' }, | ||
{ value: 12, label: '乌鲁木齐市' }, | ||
], | ||
] | ||
|
||
return ( | ||
<> | ||
<Cell> | ||
<PickerView | ||
style={{ '--nutui-picker-item-height': '28px' }} | ||
options={listData} | ||
defaultValue={[1]} | ||
onChange={({ value, selectedOptions }) => { | ||
console.log('onChange', value, selectedOptions) | ||
}} | ||
/> | ||
</Cell> | ||
</> | ||
) | ||
} | ||
export default Demo2 |
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
建议重构以减少代码重复
H5 和 Taro 版本的 Demo2 代码几乎完全相同,建议:
- 创建一个共享的基础组件
- 根据平台差异进行必要的封装
+ // shared/demos/picker-demo2.tsx
+ import React from 'react'
+
+ export const createPickerDemo2 = (PickerView: any, Cell: any) => {
+ return () => {
+ const listData = [/* ... */]
+
+ return (
+ <Cell>
+ <PickerView
+ style={{ '--nutui-picker-item-height': '28px' }}
+ options={listData}
+ defaultValue={[1]}
+ onChange={/* ... */}
+ />
+ </Cell>
+ )
+ }
+ }
+ // h5/demo2.tsx
+ import { PickerView, Cell } from '@nutui/nutui-react'
+ import { createPickerDemo2 } from '../shared/demos/picker-demo2'
+ export default createPickerDemo2(PickerView, Cell)
+ // taro/demo2.tsx
+ import { PickerView, Cell } from '@nutui/nutui-react-taro'
+ import { createPickerDemo2 } from '../shared/demos/picker-demo2'
+ export default createPickerDemo2(PickerView, Cell)
📝 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.
import React from 'react' | |
import { PickerView, Cell } from '@nutui/nutui-react-taro' | |
const Demo2 = () => { | |
const listData = [ | |
[ | |
{ value: 1, label: '南京市' }, | |
{ value: 2, label: '无锡市' }, | |
{ value: 3, label: '海北藏族自治区' }, | |
{ value: 4, label: '北京市' }, | |
{ value: 5, label: '连云港市' }, | |
{ value: 8, label: '大庆市' }, | |
{ value: 9, label: '绥化市' }, | |
{ value: 10, label: '潍坊市' }, | |
{ value: 12, label: '乌鲁木齐市' }, | |
], | |
] | |
return ( | |
<> | |
<Cell> | |
<PickerView | |
style={{ '--nutui-picker-item-height': '28px' }} | |
options={listData} | |
defaultValue={[1]} | |
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
/> | |
</Cell> | |
</> | |
) | |
} | |
export default Demo2 | |
// shared/demos/picker-demo2.tsx | |
import React from 'react' | |
export const createPickerDemo2 = (PickerView: any, Cell: any) => { | |
return () => { | |
const listData = [ | |
[ | |
{ value: 1, label: '南京市' }, | |
{ value: 2, label: '无锡市' }, | |
{ value: 3, label: '海北藏族自治区' }, | |
{ value: 4, label: '北京市' }, | |
{ value: 5, label: '连云港市' }, | |
{ value: 8, label: '大庆市' }, | |
{ value: 9, label: '绥化市' }, | |
{ value: 10, label: '潍坊市' }, | |
{ value: 12, label: '乌鲁木齐市' }, | |
], | |
] | |
return ( | |
<Cell> | |
<PickerView | |
style={{ '--nutui-picker-item-height': '28px' }} | |
options={listData} | |
defaultValue={[1]} | |
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
/> | |
</Cell> | |
) | |
} | |
} |
import React from 'react' | |
import { PickerView, Cell } from '@nutui/nutui-react-taro' | |
const Demo2 = () => { | |
const listData = [ | |
[ | |
{ value: 1, label: '南京市' }, | |
{ value: 2, label: '无锡市' }, | |
{ value: 3, label: '海北藏族自治区' }, | |
{ value: 4, label: '北京市' }, | |
{ value: 5, label: '连云港市' }, | |
{ value: 8, label: '大庆市' }, | |
{ value: 9, label: '绥化市' }, | |
{ value: 10, label: '潍坊市' }, | |
{ value: 12, label: '乌鲁木齐市' }, | |
], | |
] | |
return ( | |
<> | |
<Cell> | |
<PickerView | |
style={{ '--nutui-picker-item-height': '28px' }} | |
options={listData} | |
defaultValue={[1]} | |
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
/> | |
</Cell> | |
</> | |
) | |
} | |
export default Demo2 | |
// src/packages/pickerview/demos/taro/demo2.tsx | |
import { PickerView, Cell } from '@nutui/nutui-react-taro' | |
import { createPickerDemo2 } from '../shared/demos/picker-demo2' | |
export default createPickerDemo2(PickerView, Cell) |
import React from 'react' | |
import { PickerView, Cell } from '@nutui/nutui-react-taro' | |
const Demo2 = () => { | |
const listData = [ | |
[ | |
{ value: 1, label: '南京市' }, | |
{ value: 2, label: '无锡市' }, | |
{ value: 3, label: '海北藏族自治区' }, | |
{ value: 4, label: '北京市' }, | |
{ value: 5, label: '连云港市' }, | |
{ value: 8, label: '大庆市' }, | |
{ value: 9, label: '绥化市' }, | |
{ value: 10, label: '潍坊市' }, | |
{ value: 12, label: '乌鲁木齐市' }, | |
], | |
] | |
return ( | |
<> | |
<Cell> | |
<PickerView | |
style={{ '--nutui-picker-item-height': '28px' }} | |
options={listData} | |
defaultValue={[1]} | |
onChange={({ value, selectedOptions }) => { | |
console.log('onChange', value, selectedOptions) | |
}} | |
/> | |
</Cell> | |
</> | |
) | |
} | |
export default Demo2 | |
// h5/demo2.tsx | |
import { PickerView, Cell } from '@nutui/nutui-react' | |
import { createPickerDemo2 } from '../shared/demos/picker-demo2' | |
export default createPickerDemo2(PickerView, Cell) |
selectedOptions.forEach((option: any) => { | ||
description += ` ${option.label}` | ||
}) |
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
建议改进类型安全性
在 forEach 循环中使用 any
类型不够安全。应该使用 PickerOptionItem
类型。
建议如下修改:
- selectedOptions.forEach((option: any) => {
+ selectedOptions.forEach((option: PickerOptionItem) => {
description += ` ${option.label}`
})
📝 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.
selectedOptions.forEach((option: any) => { | |
description += ` ${option.label}` | |
}) | |
selectedOptions.forEach((option: PickerOptionItem) => { | |
description += ` ${option.label}` | |
}) |
}, | ||
{ | ||
value: 4, | ||
text: '东城区', | ||
}, | ||
{ | ||
value: 5, | ||
text: '西城区', | ||
}, | ||
{ | ||
value: 6, | ||
text: '丰台区', | ||
}, | ||
], | ||
}, | ||
{ | ||
value: 2, | ||
text: '上海', | ||
children: [ | ||
{ | ||
value: 1, | ||
text: '黄埔区', | ||
}, | ||
{ | ||
value: 2, | ||
text: '长宁区', | ||
}, | ||
{ | ||
value: 3, | ||
text: '普陀区', | ||
}, | ||
{ | ||
value: 4, | ||
text: '杨浦区', | ||
}, | ||
{ | ||
value: 5, | ||
text: '浦东新区', | ||
}, | ||
], | ||
}, | ||
[ | ||
{ | ||
value: 1, | ||
label: '北京', | ||
children: [ | ||
{ | ||
value: 1, | ||
label: '朝阳区', | ||
}, | ||
{ | ||
value: 2, | ||
label: '海淀区', | ||
}, | ||
{ | ||
value: 3, | ||
label: '大兴区', | ||
}, | ||
{ | ||
value: 4, | ||
label: '东城区', | ||
}, | ||
{ | ||
value: 5, | ||
label: '西城区', | ||
}, | ||
{ | ||
value: 6, | ||
label: '丰台区', | ||
}, | ||
], | ||
}, | ||
{ | ||
value: 2, | ||
label: '上海', | ||
children: [ | ||
{ | ||
value: 1, | ||
label: '黄埔区', | ||
}, | ||
{ | ||
value: 2, | ||
label: '长宁区', | ||
}, | ||
{ | ||
value: 3, | ||
label: '普陀区', | ||
}, | ||
{ | ||
value: 4, | ||
label: '杨浦区', | ||
}, | ||
{ | ||
value: 5, | ||
label: '浦东新区', | ||
}, | ||
], | ||
}, | ||
], | ||
] |
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
建议提取共享的数据和工具函数
h5 和 taro 版本的 demo 中存在大量重复的数据结构和逻辑。建议将这些共同部分提取到共享文件中。
建议创建一个共享的数据文件:
// shared/cityData.ts
export const customCityData = [
[
{
value: 1,
label: '北京',
children: [
// ... existing data
],
},
// ... remaining data
],
]
然后在两个 demo 文件中导入:
-const customCityData = [ ... ]
+import { customCityData } from '../shared/cityData'
if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { | ||
console.log('updateChooseValueCustmer', index, value, selectedOptions) | ||
setTimeout(() => { | ||
if (asyncData[1].children.length === 0) { | ||
asyncData[1].children = [ | ||
{ | ||
value: 1, | ||
text: '黄埔区', | ||
}, | ||
{ | ||
value: 2, | ||
text: '长宁区', | ||
}, | ||
{ | ||
value: 3, | ||
text: '普陀区', | ||
}, | ||
{ | ||
value: 4, | ||
text: '杨浦区', | ||
}, | ||
{ | ||
value: 5, | ||
text: '浦东新区', | ||
}, | ||
] | ||
setAsyncData([...asyncData]) | ||
} | ||
}, 100) | ||
asyncData[0][1].children = [ | ||
{ | ||
value: 1, | ||
label: '黄埔区', | ||
}, | ||
{ | ||
value: 2, | ||
label: '长宁区', | ||
}, | ||
{ | ||
value: 3, | ||
label: '普陀区', | ||
}, | ||
{ | ||
value: 4, | ||
label: '杨浦区', | ||
}, | ||
{ | ||
value: 5, | ||
label: '浦东新区', | ||
}, | ||
] | ||
setAsyncData([...[...asyncData]]) | ||
}, 0) |
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(fn, 0) 是一种反模式
建议使用不可变的方式更新状态:
- asyncData[0][1].children = [
- // ... data
- ]
- setAsyncData([...[...asyncData]])
+ setAsyncData((prevData) => {
+ const newData = JSON.parse(JSON.stringify(prevData))
+ newData[0][1].children = [
+ // ... data
+ ]
+ return newData
+ })
对于异步数据加载,建议:
- 使用 Promise 或 async/await
- 添加加载状态指示
- 实现错误处理机制
📝 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 (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { | |
console.log('updateChooseValueCustmer', index, value, selectedOptions) | |
setTimeout(() => { | |
if (asyncData[1].children.length === 0) { | |
asyncData[1].children = [ | |
{ | |
value: 1, | |
text: '黄埔区', | |
}, | |
{ | |
value: 2, | |
text: '长宁区', | |
}, | |
{ | |
value: 3, | |
text: '普陀区', | |
}, | |
{ | |
value: 4, | |
text: '杨浦区', | |
}, | |
{ | |
value: 5, | |
text: '浦东新区', | |
}, | |
] | |
setAsyncData([...asyncData]) | |
} | |
}, 100) | |
asyncData[0][1].children = [ | |
{ | |
value: 1, | |
label: '黄埔区', | |
}, | |
{ | |
value: 2, | |
label: '长宁区', | |
}, | |
{ | |
value: 3, | |
label: '普陀区', | |
}, | |
{ | |
value: 4, | |
label: '杨浦区', | |
}, | |
{ | |
value: 5, | |
label: '浦东新区', | |
}, | |
] | |
setAsyncData([...[...asyncData]]) | |
}, 0) | |
if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { | |
console.log('updateChooseValueCustmer', index, value, selectedOptions) | |
setTimeout(() => { | |
setAsyncData((prevData) => { | |
const newData = JSON.parse(JSON.stringify(prevData)) | |
newData[0][1].children = [ | |
{ | |
value: 1, | |
label: '黄埔区', | |
}, | |
{ | |
value: 2, | |
label: '长宁区', | |
}, | |
{ | |
value: 3, | |
label: '普陀区', | |
}, | |
{ | |
value: 4, | |
label: '杨浦区', | |
}, | |
{ | |
value: 5, | |
label: '浦东新区', | |
}, | |
] | |
return newData | |
}) | |
}, 0) | |
} |
const columns = container.querySelectorAll('.nut-pickerview-list')[0] | ||
const lists = columns.querySelectorAll('.nut-pickerview-roller-item-title') | ||
expect(lists.length).toBe(3) |
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.
修复测试失败!
CI 管道显示此处的断言失败。需要验证选择器和预期的列表长度是否正确。
- const columns = container.querySelectorAll('.nut-pickerview-list')[0]
- const lists = columns.querySelectorAll('.nut-pickerview-roller-item-title')
+ const columns = container.querySelectorAll('.nut-pickerview-list')
+ const lists = columns[0].querySelectorAll('.nut-pickerview-roller-item-title')
expect(lists.length).toBe(3)
📝 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.
const columns = container.querySelectorAll('.nut-pickerview-list')[0] | |
const lists = columns.querySelectorAll('.nut-pickerview-roller-item-title') | |
expect(lists.length).toBe(3) | |
const columns = container.querySelectorAll('.nut-pickerview-list') | |
const lists = columns[0].querySelectorAll('.nut-pickerview-roller-item-title') | |
expect(lists.length).toBe(3) |
🧰 Tools
🪛 GitHub Actions: CI
[error] 45-45: AssertionError: expected +0 to be 3 // Object.is equality
test('should match onchange', async () => { | ||
const PenderContent = () => { | ||
const [value, setValue] = useState([]) | ||
const [options, setInnerOptions] = useState<PickerOptions[]>([]) | ||
|
||
useEffect(() => { | ||
const timer = setTimeout(() => { | ||
setInnerOptions(listData) | ||
setValue([1]) | ||
}, 1000) | ||
|
||
return () => clearTimeout(timer) // 清理定时器 | ||
}, []) | ||
|
||
return ( | ||
<PickerView | ||
value={value} | ||
options={options} | ||
onChange={({ value }) => { | ||
if (value[0] === 1) { | ||
setValue([3]) | ||
} | ||
}} | ||
/> | ||
) | ||
} | ||
|
||
const { container } = render(<PenderContent />) | ||
|
||
await waitFor(() => { | ||
expect(container).toMatchSnapshot() | ||
}) | ||
}) |
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
异步更新测试需要优化。
当前的异步测试使用了固定的延时时间(1000ms),这可能导致测试不稳定。建议使用 act
包装异步操作,并考虑使用更可靠的等待机制。
- const timer = setTimeout(() => {
- setInnerOptions(listData)
- setValue([1])
- }, 1000)
+ await act(async () => {
+ setInnerOptions(listData)
+ setValue([1])
+ })
Committable suggestion skipped: line range outside the PR's diff.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat_v3.x #2990 +/- ##
=============================================
+ Coverage 85.79% 85.89% +0.09%
=============================================
Files 281 280 -1
Lines 18527 18189 -338
Branches 2810 2741 -69
=============================================
- Hits 15896 15623 -273
+ Misses 2626 2561 -65
Partials 5 5 ☔ View full report in Codecov by Sentry. |
🤔 这个变动的性质是?
🔗 相关 Issue
💡 需求背景和解决方案
☑️ 请求合并前的自查清单
Summary by CodeRabbit