-
Notifications
You must be signed in to change notification settings - Fork 619
feat: 评分 rate #1455
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
base: 5.5.0
Are you sure you want to change the base?
feat: 评分 rate #1455
Conversation
Summary of ChangesHello @lqr131115, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request adds a new Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 Walkthrough概览在 React Native 项目中新增完整的 Rate(评分)组件,包括核心实现、类型定义、样式、动画支持、工具函数、文档、演示与测试,并在 变更
序列图sequenceDiagram
participant User
participant Rate as Rate 组件
participant Pan as PanResponder
participant State as 内部状态
participant Anim as AnimatedIcon
User->>Rate: 点击或滑动评分区域
Rate->>Pan: 接收手势事件(start/move/end)
Pan->>State: 计算并更新 internalValue(含半星与 RTL 处理)
Rate->>Rate: 使用 getStars 生成星态数组
Rate->>Anim: 对被激活星位触发动画(active=true)
Anim->>Anim: 执行缩放动画(1 → scale)
Rate->>User: 渲染更新后的星图标
Note over Rate: 释放手势后触发 onChange/onRatingEnd;若 allowClear 并重复点击同一值则清除
代码审查工作量🎯 3 (中等复杂度) | ⏱️ ~25 分钟 诗
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new Rate component, which is a great addition. The implementation is comprehensive, covering features like half-star rating, swiping, clearing, and animations. The code is well-structured with separate files for props, styles, and utility functions.
I've left a few comments with suggestions for improvement, mainly focusing on performance optimization in PanResponder usage, improving type safety, removing a magic number, and addressing some minor code duplication and inconsistencies. Overall, this is a solid contribution.
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: 3
🧹 Nitpick comments (11)
components/rate/utils.ts (1)
1-9: 函数逻辑正确,可以考虑添加更具体的返回类型。getStars 函数的逻辑正确处理了满星、半星和空星的状态。
可以考虑为返回值添加更具体的类型注解以提高类型安全性:
-export function getStars(rating: number, maxStars: number) { +export function getStars(rating: number, maxStars: number): ('full' | 'half' | 'empty')[] { return [...Array(maxStars)].map((_, i) => {components/rate/index.zh-CN.md (1)
28-29: 建议简化默认值描述。默认值列中的描述信息有些冗余。默认值应该简洁明了。
-| iconName | 图标名称 | `string` | `star`, 默认星星 | -| iconType | 图标类型 | `fill | outline` | `fill`, 实底风格 | +| iconName | 图标名称 | `string` | `star` | +| iconType | 图标类型 | `fill | outline` | `fill` |components/rate/demo/basic.md (1)
14-15: 示例中Item来源错误,应为List.Item。
当前写成Popover.Item且未导入 Popover,复制运行会报错。建议更正:-const Item = Popover.Item +const Item = List.Itemcomponents/rate/RateIcon.tsx (2)
6-22: 避免向底层 Icon 透传未知属性并收紧类型。
emptyColor不应再透传到IconFill/IconOutline;同时移除any。-const Icon = ({ - size, - name, - color, - emptyColor, - isFill, -}: Omit<RateIconProps, 'type'>) => { - const IconComponent: any = isFill ? IconFill : IconOutline - return ( - <IconComponent - size={size} - color={color} - name={name} - emptyColor={emptyColor} - /> - ) -} +const Icon = ({ + size, + name, + color, + isFill, +}: Omit<RateIconProps, 'type' | 'emptyColor'>) => { + const IconComponent: typeof IconFill | typeof IconOutline = isFill + ? IconFill + : IconOutline + return <IconComponent size={size} color={color} name={name} /> +}
46-82: 请验证 RTL 下半星裁剪是否正确且无缝。
容器在 RTL 时整体rotateY(180deg),第二半区块也固定rotateY(180deg),存在“双重镜像”风险,某些像素密度下两半之间可能出现细缝。建议:
- 视觉验收 RTL/LTR(深浅背景、不同尺寸、不同颜色)。
- 如有缝隙,改为“叠放两层绝对定位图标 + 宽度裁剪”避免缝隙。
components/rate/AnimatedIcon.tsx (1)
13-17: 补齐delay支持并改进清理函数。
与defaultAnimationConfig保持一致,避免忽略用户自定义的 delay。const { - scale = defaultAnimationConfig.scale, - easing = defaultAnimationConfig.easing, - duration = defaultAnimationConfig.duration, + scale = defaultAnimationConfig.scale, + easing = defaultAnimationConfig.easing, + duration = defaultAnimationConfig.duration, + delay = defaultAnimationConfig.delay, } = config @@ - React.useEffect(() => { - const animation = Animated.timing(animatedSize.current, { - toValue: active ? scale : 1, - useNativeDriver: true, - easing, - duration, - }) - - animation.start() - return animation.stop - }, [active, scale, easing, duration]) + React.useEffect(() => { + const animation = Animated.timing(animatedSize.current, { + toValue: active ? scale : 1, + useNativeDriver: true, + easing, + duration, + delay, + }) + animation.start() + return () => animation.stop() + }, [active, scale, easing, duration, delay])Also applies to: 21-31
components/rate/index.tsx (5)
130-142: 与动画配置保持一致:使用合并后的delay。
这里应使用memoAnimationOptions.config.delay,否则用户自定义delay无效。- setTimeout(() => { - setInteracting(false) - }, defaultAnimationConfig.delay) + setTimeout(() => { + setInteracting(false) + }, memoAnimationOptions.config.delay)同理建议在
onPanResponderTerminate中也替换为memoAnimationOptions.config.delay。
176-176: 样式合并用数组,避免丢失样式与提升性能。
RN 推荐style={[a, b]},对象展开会丢失数组样式且有额外开销。- style={{ ...styles.icon, ...iconStyle }}> + style={[styles.icon, iconStyle]}>
66-71: 评分取整中的+ 0.2偏移请确认依据。
该偏移会提前晋级到下一半星,易引发边界感知不一致。建议:
- 说明设计依据或加入注释;
- 或将偏移提取为常量(并允许配置);
- 或移除偏移,仅基于标准舍入。
134-142: 终止回调可能传递-1。
onPanResponderTerminate用endRating.current,若从未移动则为-1。建议回退到internalValue:- onPanResponderTerminate: () => { - // called when user drags outside of the component - onRatingEnd?.(endRating.current) + onPanResponderTerminate: () => { + // called when user drags outside of the component + onRatingEnd?.(endRating.current >= 0 ? endRating.current : internalValue) endRating.current = -1 startRating.current = -1 - setTimeout(() => { - setInteracting(false) - }, defaultAnimationConfig.delay) + setTimeout(() => { + setInteracting(false) + }, memoAnimationOptions.config.delay) },
12-31: API 一致性:iconFill与iconType存在重叠。
PropsType 同时暴露iconFill?: boolean与iconType?: 'fill' | 'outline',但实现仅使用iconType。建议统一一个 API,并在文档中标注另一个为废弃或移除。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
components/rate/__tests__/__snapshots__/demo.test.js.snapis excluded by!**/*.snaptests/__snapshots__/index.test.js.snapis excluded by!**/*.snap
📒 Files selected for processing (15)
components/index.tsx(1 hunks)components/rate/AnimatedIcon.tsx(1 hunks)components/rate/PropsType.tsx(1 hunks)components/rate/RateIcon.tsx(1 hunks)components/rate/__tests__/demo.test.js(1 hunks)components/rate/constants.ts(1 hunks)components/rate/demo/basic.md(1 hunks)components/rate/demo/basic.tsx(1 hunks)components/rate/index.en-US.md(1 hunks)components/rate/index.tsx(1 hunks)components/rate/index.zh-CN.md(1 hunks)components/rate/style/index.tsx(1 hunks)components/rate/utils.ts(1 hunks)components/types.ts(1 hunks)rn-kitchen-sink/demoList.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
components/rate/AnimatedIcon.tsx (2)
components/rate/PropsType.tsx (1)
AnimatedIconProps(53-58)components/rate/constants.ts (1)
defaultAnimationConfig(4-9)
components/rate/__tests__/demo.test.js (1)
tests/shared/demoTest.js (1)
rnDemoTest(6-24)
components/rate/index.tsx (5)
components/rate/PropsType.tsx (2)
RateProps(10-30)AnimationOptions(48-51)components/rate/constants.ts (1)
defaultAnimationConfig(4-9)components/style/index.tsx (1)
WithTheme(68-92)components/rate/style/index.tsx (2)
RateStyle(4-7)theme(9-18)components/rate/utils.ts (1)
getStars(1-9)
components/rate/demo/basic.tsx (1)
components/flex/Flex.tsx (1)
Flex(19-84)
components/rate/RateIcon.tsx (2)
components/icon/index.tsx (1)
Icon(15-44)components/rate/PropsType.tsx (1)
RateIconProps(32-39)
components/rate/constants.ts (1)
components/rate/PropsType.tsx (1)
AnimationConfig(41-46)
components/rate/PropsType.tsx (1)
components/types.ts (1)
RateProps(49-49)
🔇 Additional comments (9)
components/rate/__tests__/demo.test.js (1)
1-3: 测试文件结构正确。测试文件遵循了项目中其他组件的标准模式,正确使用共享的 demoTest 工具来测试 Rate 组件的 demo。
components/index.tsx (1)
38-38: Rate 组件导出正确。Rate 组件的导出遵循了现有模式,并且按字母顺序正确放置在 Radio 和 Result 之间。
components/types.ts (1)
49-49: RateProps 类型导出正确。RateProps 类型的导出遵循了现有模式,并且按字母顺序正确放置。
rn-kitchen-sink/demoList.js (1)
194-199: Rate demo 配置正确。Rate demo 配置项遵循了现有的结构模式,正确放置在 UICONTROLS 部分,并且包含了所有必需的字段。
components/rate/style/index.tsx (1)
1-18: 样式定义正确且遵循最佳实践。Rate 组件的样式定义遵循了项目中其他组件的标准模式:
- 使用 StyleSheet.create 创建样式
- 通过 Theme 使用一致的间距值
- rateContainer 的 flexDirection 和 alignSelf 设置适合水平排列的星星布局
components/rate/constants.ts (1)
4-9: 默认动画配置设计合理,类型严格,直接可用。
覆盖了 easing/duration/scale/delay 且与 AnimationConfig 对齐,无需改动。components/rate/demo/basic.tsx (1)
1-6: Demo 覆盖场景全面,接口使用正确。
示例可直接跑通,便于验证交互。components/rate/PropsType.tsx (2)
10-30: 接口设计良好!
RateProps接口结构完整且合理:
- 支持受控/非受控模式(value/defaultValue)
- 提供了丰富的交互配置选项
animationConfig?: boolean | AnimationConfig的设计很好,既支持简单的开关,也支持自定义配置- 回调函数涵盖了评分的完整生命周期
32-58: 类型定义清晰且一致!剩余的类型定义都很合理:
RateIconProps:为单个图标提供了必要的渲染属性AnimationConfig:所有字段可选,提供了灵活的动画配置AnimationOptions:正确使用Required<AnimationConfig>确保内部使用时所有配置都存在AnimatedIconProps:为动画包装组件提供了合适的属性接口类型层次结构清晰,各类型职责分明。
|
展示效果:#1456 |
First of all, thank you for your contribution! :-)
Please makes sure that these checkboxes are checked before submitting your PR, thank you!
npm run lintand fix those errors before submitting in order to keep consistent code style.Extra checklist:
if isBugFix :
elif isNewFeature :
Summary by CodeRabbit
新功能
文档
示例与演示
测试