Skip to content

Conversation

@codewithshinde
Copy link
Contributor

@codewithshinde codewithshinde commented Jul 18, 2025

Motivation

Fixes # (issue) react-native-ratings Issues

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • [ x] New feature (non-breaking change which adds functionality)
  • [x ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • Jest Unit Test
  • [x ] Checked with example app

Checklist

  • [x ] My code follows the style guidelines of this project
  • [x ] I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation using yarn docs-build-api
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Additional context

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR removes the external react-native-ratings dependency and implements a custom in-house rating solution by creating new AirbnbRating components with TapRating and SwipeRating functionality. This represents a breaking change that internalizes rating functionality within the react-native-elements library.

  • Removes react-native-ratings dependency from multiple package.json files
  • Implements custom TapRating and SwipeRating components from scratch
  • Updates Rating and AirbnbRating components to use the new internal implementation

Reviewed Changes

Copilot reviewed 12 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
website/package.json Removes react-native-ratings dependency from website package
packages/base/package.json Removes react-native-ratings dependency and updates testing dependencies
package.json Updates testing library versions and Jest configuration
packages/base/src/Rating/Rating.tsx Updates imports to use new internal SwipeRating component
packages/base/src/AirbnbRating/AirbnbRating.tsx Updates imports to use new internal TapRating component
packages/base/src/AirbnbRating/TapRating.tsx New custom TapRating component implementation
packages/base/src/AirbnbRating/SwipeRating.tsx New custom SwipeRating component implementation
packages/base/src/AirbnbRating/components/Star.tsx New Star component for rating functionality
Comments suppressed due to low confidence (1)

packages/base/src/AirbnbRating/tests/SwipeRating.test.tsx:5

  • This test is checking for exports from '../index' but the file being tested is SwipeRating.test.tsx. The test should actually test the SwipeRating component functionality rather than checking index exports.
    const { Rating, AirbnbRating } = require('../index');

Comment on lines +310 to +311
// eslint-disable-next-line react-hooks/exhaustive-deps
[] // [getCurrentRating, onStartRating, position]
Copy link

Copilot AI Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The eslint-disable comment with empty dependency array is potentially problematic. The callback relies on getCurrentRating, onStartRating, and position which should be included in the dependency array or the disable comment should be justified.

Suggested change
// eslint-disable-next-line react-hooks/exhaustive-deps
[] // [getCurrentRating, onStartRating, position]
[getCurrentRating, onStartRating, position]

Copilot uses AI. Check for mistakes.
Comment on lines +323 to +324
// eslint-disable-next-line react-hooks/exhaustive-deps
[] // [getCurrentRating, onSwipeRating, position]
Copy link

Copilot AI Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the previous callback, this eslint-disable comment with empty dependency array is potentially problematic. The callback uses getCurrentRating, onSwipeRating, and position which should be in the dependency array.

Suggested change
// eslint-disable-next-line react-hooks/exhaustive-deps
[] // [getCurrentRating, onSwipeRating, position]
[getCurrentRating, onSwipeRating, position]

Copilot uses AI. Check for mistakes.
},
//
// eslint-disable-next-line react-hooks/exhaustive-deps
[] // [getCurrentRating, fractions, onFinishRating, setCurrentRating, minValue]
Copy link

Copilot AI Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This eslint-disable comment with empty dependency array is also problematic. The callback depends on several functions and values that should be included in the dependency array to prevent stale closures.

Suggested change
[] // [getCurrentRating, fractions, onFinishRating, setCurrentRating, minValue]
[getCurrentRating, fractions, onFinishRating, setCurrentRating, minValue, ratingBackdropValue]

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +74
//@ts-ignore
const fractionsType: any = (props, propName, componentName) => {
if (props[propName]) {
const value = props[propName];

if (typeof value === 'number') {
return value >= 0 && value <= 20
? null
: new Error(
`\`${propName}\` in \`${componentName}\` must be between 0 and 20`
);
}

return new Error(
`\`${propName}\` in \`${componentName}\` must be a number`
);
}
};

Copy link

Copilot AI Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @ts-ignore to suppress TypeScript errors is not ideal. The fractionsType function should be properly typed instead of being suppressed.

Suggested change
//@ts-ignore
const fractionsType: any = (props, propName, componentName) => {
if (props[propName]) {
const value = props[propName];
if (typeof value === 'number') {
return value >= 0 && value <= 20
? null
: new Error(
`\`${propName}\` in \`${componentName}\` must be between 0 and 20`
);
}
return new Error(
`\`${propName}\` in \`${componentName}\` must be a number`
);
}
};
const fractionsType: (props: Record<string, any>, propName: string, componentName: string) => Error | null =
(props, propName, componentName) => {
if (props[propName]) {
const value = props[propName];
if (typeof value === 'number') {
return value >= 0 && value <= 20
? null
: new Error(
`\`${propName}\` in \`${componentName}\` must be between 0 and 20`
);
}
return new Error(
`\`${propName}\` in \`${componentName}\` must be a number`
);
}
return null;
};

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@theianmay
Copy link
Member

theianmay commented Oct 23, 2025

Thank you @codewithshinde for making the subsequent updates so that all checks are now passing. I tested on the example app locally and all yarn test tests are passing, so we should be ready to merge this PR. I am documenting my detailed review below. In summary, there is 1 ESLint warning and 2 smaller things that I noted.

Additionally, I added a "Future Improvement" section below to address the above note from Copilot:
Using @ts-ignore to suppress TypeScript errors is not ideal. The fractionsType function should be properly typed instead of being suppressed.
We can tackle that later in a separate PR.

I leveraged Claude to assist in my review of the react-native-ratings integration and the code looks solid. The implementation is correct and properly linked through to the example app.

Review

  • Component Structure - All rating components properly implemented with correct wrapper pattern
  • Imports/Exports - Correctly chained from base → themed → example app
  • Example App Integration - ratings.tsx correctly imports and uses both Rating and AirbnbRating
  • Assets - All 6 rating images present in packages/base/src/AirbnbRating/images/
  • TypeScript Types - Props properly exported and typed
  • Tests - Test files exist for both SwipeRating and TapRating
  • Module Resolution - Babel config correctly maps @rneui/base and @rneui/themed for local development

Suggested Future Changes

1. Fix Variable Shadowing in TapRating

Location: packages/base/src/AirbnbRating/TapRating.tsx line 147

Issue: The function parameter position shadows the state variable position declared on line 133, causing an ESLint warning: 'position' is already declared in the upper scope.

Suggested Fix:

Rename the parameter to avoid shadowing:

- const starSelectedInPosition = (position: number) => {
+ const starSelectedInPosition = (selectedPosition: number) => {
    if (typeof onFinishRating === 'function') {
-     onFinishRating(position);
+     onFinishRating(selectedPosition);
    }
-   setPosition(position);
+   setPosition(selectedPosition);
  };

2. [Nitpick] Remove Unused Dependency

In packages/base/package.json, the dependency "@rn-vui/ratings": "^0.5.0" is not imported anywhere in the codebase. Since you've integrated the code directly, this should be removed:

  "dependencies": {
-   "@rn-vui/ratings": "^0.5.0",
    "@types/react-native-vector-icons": "^6.4.10",
    "color": "^3.2.1",

After removing, run yarn install in the packages/base directory to update the lockfile.

3. [Nitpick] Remove Outdated Comment

In packages/base/src/AirbnbRating/AirbnbRating.tsx line 2, there's a misleading comment:

 import React from 'react';
-// Assuming TapRating and SwipeRating are now available at the root level of 'react-native-ratings'
 import TapRating, { type TapRatingProps as RatingProps } from './TapRating';

This comment references react-native-ratings but the code imports from local files './TapRating', so it should be removed.

Future Improvement Suggested: fractions Runtime Validation

This section is to address the above note from Copilot:
Using @ts-ignore to suppress TypeScript errors is not ideal. The fractionsType function should be properly typed instead of being suppressed.

Location: packages/base/src/AirbnbRating/SwipeRating.tsx lines 56-73, 171

Issue: The [fractionsType] validator is never executed. The component uses fractions with .toFixed() which throws a RangeError if fractions < 0 or fractions > 100.

Suggested Fix:

  1. Remove the unused validator (lines 56-73)
  2. Change type definition:
-  fractions?: typeof fractionsType;
+  fractions?: number;
  1. Add runtime validation in component:
React.useEffect(() => {
  if (fractions !== undefined && (fractions < 0 || fractions > 20)) {
    console.error(`[SwipeRating] fractions must be between 0-20, received ${fractions}`);
  }
}, [fractions]);

Priority: Medium - Should be addressed in a separate, follow-up PR.

Additional Note Re: Copilot Comments
Test Structure: The test structure is correct. index.test.tsx tests exports, while component-specific test files test functionality. This is a standard testing pattern.
Dependency Arrays in SwipeRating.tsx: The empty dependency arrays in panResponderOnGrant, panResponderOnMove, and panResponderOnRelease are intentional performance optimizations to prevent PanResponder recreation. This is a common pattern in React Native gesture handling when callbacks are stable. The commented-out dependencies show this was a conscious decision. While technically Copilot is correct about exhaustive-deps, this optimization is acceptable for this use case. If you want to add clarity, consider adding a comment explaining the intentional optimization above each eslint-disable, but as we discussed via Discord, many of these comment lines were from the older files that are being brought in so I think it is OK to leave as is for now.

@theianmay
Copy link
Member

Potential Bug from Manual Testing

While doing further testing on the example app's ratings screen, I discovered that custom rating images don't work as expected in the SwipeRating component. When you set type="custom" and provide a ratingImage prop (like the water droplet example on line 79-88 of ratings.tsx), the component ignores the custom image and displays stars instead. This seems to be a bug in SwipeRating.tsx line 405 where it always uses the hardcoded type lookup instead of checking for the ratingImage prop when type="custom". The test that would have caught this (line 36-46 of SwipeRating.test.tsx) was commented out. I'll open a separate issue and then address in a separate PR to fix the image source logic and re-enable the test.

@theianmay theianmay merged commit 5f68c75 into react-native-elements:next Oct 26, 2025
5 checks passed
github-actions bot pushed a commit to theianmay/react-native-elements that referenced this pull request Oct 26, 2025
…ns/main

fix:react-native-ratings integration in react-native-elements
github-actions bot pushed a commit to theianmay/react-native-elements that referenced this pull request Oct 26, 2025
…ns/main

fix:react-native-ratings integration in react-native-elements
@theianmay theianmay added this to the v5.0.0 milestone Nov 16, 2025
@github-project-automation github-project-automation bot moved this to Closed or Merged 🏁 in Community Roadmap 🛣 Nov 16, 2025
@theianmay theianmay self-requested a review December 5, 2025 06:47
Copy link
Member

@theianmay theianmay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full review in comment above, merged and closed, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Closed or Merged 🏁

Development

Successfully merging this pull request may close these issues.

2 participants